diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py
index 43aaa2f58c1..a380a69dc03 100644
--- a/addons/account/__openerp__.py
+++ b/addons/account/__openerp__.py
@@ -99,7 +99,6 @@ for a particular financial year and for preparation of vouchers there is a modul
'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.xml',
'account_invoice_view.xml',
- 'partner_view.xml',
'data/account_data.xml',
'data/data_account_type.xml',
'data/configurable_account_chart.xml',
@@ -112,6 +111,7 @@ for a particular financial year and for preparation of vouchers there is a modul
'project/wizard/account_analytic_journal_report_view.xml',
'project/wizard/account_analytic_cost_ledger_for_journal_report_view.xml',
'project/wizard/account_analytic_chart_view.xml',
+ 'partner_view.xml',
'product_view.xml',
'account_assert_test.xml',
'process/statement_process.xml',
diff --git a/addons/account/account.py b/addons/account/account.py
index 3959799f1bb..33b52b643ed 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -648,10 +648,10 @@ class account_account(osv.osv):
if line_obj.search(cr, uid, [('account_id', 'in', account_ids)]):
#Check for 'Closed' type
if old_type == 'closed' and new_type !='closed':
- raise osv.except_osv(_('Warning !'), _("You cannot change the type of account from 'Closed' to any other type as it contains journal items!"))
+ raise osv.except_osv(_('Warning!'), _("You cannot change the type of account from 'Closed' to any other type as it contains journal items!"))
# Forbid to change an account type for restricted_groups as it contains journal items (or if one of its children does)
if (new_type in restricted_groups):
- raise osv.except_osv(_('Warning !'), _("You cannot change the type of account to '%s' type as it contains journal items!") % (new_type,))
+ raise osv.except_osv(_('Warning!'), _("You cannot change the type of account to '%s' type as it contains journal items!") % (new_type,))
return True
@@ -719,7 +719,7 @@ class account_journal(osv.osv):
'user_id': fields.many2one('res.users', 'User', help="The user responsible for this journal"),
'groups_id': fields.many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', 'Groups'),
'currency': fields.many2one('res.currency', 'Currency', help='The currency used to enter statement'),
- 'entry_posted': fields.boolean('Skip \'Draft\' State for Manual Entries', help='Check this box if you don\'t want new journal entries to pass through the \'draft\' state and instead goes directly to the \'posted state\' without any manual validation. \nNote that journal entries that are automatically created by the system are always skipping that state.'),
+ 'entry_posted': fields.boolean('Autopost Created Moves', help='Check this box to automatically post entries of this journal. Note that legally, some entries may be automatically posted when the source document is validated (Invoices), whatever the status of this field.'),
'company_id': fields.many2one('res.company', 'Company', required=True, select=1, help="Company related to this journal"),
'allow_date':fields.boolean('Check Date in Period', help= 'If set to True then do not accept the entry if the entry date is not into the period dates'),
@@ -1015,14 +1015,14 @@ class account_period(osv.osv):
if not result:
result = self.search(cr, uid, args, context=context)
if not result:
- raise osv.except_osv(_('Error !'), _('There is no period defined for this date: %s.\nPlease create one.')%dt)
+ raise osv.except_osv(_('Error!'), _('There is no period defined for this date: %s.\nPlease create one.')%dt)
return result
def action_draft(self, cr, uid, ids, *args):
mode = 'draft'
for period in self.browse(cr, uid, ids):
if period.fiscalyear_id.state == 'done':
- raise osv.except_osv(_('Warning !'), _('You can not re-open a period which belongs to closed fiscal year'))
+ raise osv.except_osv(_('Warning!'), _('You can not re-open a period which belongs to closed fiscal year'))
cr.execute('update account_journal_period set state=%s where period_id in %s', (mode, tuple(ids),))
cr.execute('update account_period set state=%s where id in %s', (mode, tuple(ids),))
return True
@@ -1034,9 +1034,15 @@ class account_period(osv.osv):
context = {}
ids = []
if name:
- ids = self.search(cr, user, [('code','ilike',name)]+ args, limit=limit)
+ ids = self.search(cr, user,
+ [('code', 'ilike', name)] + args,
+ limit=limit,
+ context=context)
if not ids:
- ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit)
+ ids = self.search(cr, user,
+ [('name', operator, name)] + args,
+ limit=limit,
+ context=context)
return self.name_get(cr, user, ids, context=context)
def write(self, cr, uid, ids, vals, context=None):
@@ -1059,10 +1065,14 @@ class account_period(osv.osv):
raise osv.except_osv(_('Error!'), _('You should choose the periods that belong to the same company.'))
if period_date_start > period_date_stop:
raise osv.except_osv(_('Error!'), _('Start period should precede then end period.'))
+
+ # /!\ We do not include a criterion on the company_id field below, to allow producing consolidated reports
+ # on multiple companies. It will only work when start/end periods are selected and no fiscal year is chosen.
+
#for period from = january, we want to exclude the opening period (but it has same date_from, so we have to check if period_from is special or not to include that clause or not in the search).
if period_from.special:
- return self.search(cr, uid, [('date_start', '>=', period_date_start), ('date_stop', '<=', period_date_stop), ('company_id', '=', company1_id)])
- return self.search(cr, uid, [('date_start', '>=', period_date_start), ('date_stop', '<=', period_date_stop), ('company_id', '=', company1_id), ('special', '=', False)])
+ return self.search(cr, uid, [('date_start', '>=', period_date_start), ('date_stop', '<=', period_date_stop)])
+ return self.search(cr, uid, [('date_start', '>=', period_date_start), ('date_stop', '<=', period_date_stop), ('special', '=', False)])
class account_journal_period(osv.osv):
@@ -1670,7 +1680,7 @@ class account_move_reconcile(osv.osv):
elif reconcile.line_partial_ids:
first_partner = reconcile.line_partial_ids[0].partner_id.id
move_lines = reconcile.line_partial_ids
- if any([line.partner_id.id != first_partner for line in move_lines]):
+ if any([(line.account_id.type in ('receivable', 'payable') and line.partner_id.id != first_partner) for line in move_lines]):
return False
return True
@@ -1854,6 +1864,12 @@ class account_tax_code(osv.osv):
_order = 'code'
+def get_precision_tax():
+ def change_digit_tax(cr):
+ res = openerp.registry(cr.dbname)['decimal.precision'].precision_get(cr, SUPERUSER_ID, 'Account')
+ return (16, res+3)
+ return change_digit_tax
+
class account_tax(osv.osv):
"""
A tax object.
@@ -1874,12 +1890,6 @@ class account_tax(osv.osv):
default.update({'name': name + _(' (Copy)')})
return super(account_tax, self).copy_data(cr, uid, id, default=default, context=context)
- def get_precision_tax():
- def change_digit_tax(cr):
- res = openerp.registry(cr.dbname)['decimal.precision'].precision_get(cr, SUPERUSER_ID, 'Account')
- return (16, res+2)
- return change_digit_tax
-
_name = 'account.tax'
_description = 'Tax'
_columns = {
@@ -2307,7 +2317,7 @@ class account_model(osv.osv):
try:
entry['name'] = model.name%{'year': move_date.strftime('%Y'), 'month': move_date.strftime('%m'), 'date': move_date.strftime('%Y-%m')}
except:
- raise osv.except_osv(_('Wrong model !'), _('You have a wrong expression "%(...)s" in your model !'))
+ raise osv.except_osv(_('Wrong Model!'), _('You have a wrong expression "%(...)s" in your model!'))
move_id = account_move_obj.create(cr, uid, {
'ref': entry['name'],
'period_id': period_id,
@@ -2319,7 +2329,7 @@ class account_model(osv.osv):
analytic_account_id = False
if line.analytic_account_id:
if not model.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
+ raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
analytic_account_id = line.analytic_account_id.id
val = {
'move_id': move_id,
@@ -2795,7 +2805,7 @@ class account_tax_template(osv.osv):
'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True),
'name': fields.char('Tax Name', size=64, required=True),
'sequence': fields.integer('Sequence', required=True, help="The sequence field is used to order the taxes lines from lower sequences to higher ones. The order is important if you have a tax that has several tax children. In this case, the evaluation order is important."),
- 'amount': fields.float('Amount', required=True, digits=(14,4), help="For Tax Type percent enter % ratio between 0-1."),
+ 'amount': fields.float('Amount', required=True, digits_compute=get_precision_tax(), help="For Tax Type percent enter % ratio between 0-1."),
'type': fields.selection( [('percent','Percent'), ('fixed','Fixed'), ('none','None'), ('code','Python Code'), ('balance','Balance')], 'Tax Type', required=True),
'applicable_type': fields.selection( [('true','True'), ('code','Python Code')], 'Applicable Type', required=True, help="If not applicable (computed through a Python code), the tax won't appear on the invoice."),
'domain':fields.char('Domain', size=32, help="This field is only used if you develop your own module allowing developers to create specific taxes in a custom domain."),
diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py
index 44411cd637a..acb0e640a7a 100644
--- a/addons/account/account_bank.py
+++ b/addons/account/account_bank.py
@@ -65,12 +65,11 @@ class bank(osv.osv):
# Find the code and parent of the bank account to create
dig = 6
current_num = 1
- ids = obj_acc.search(cr, uid, [('type','=','liquidity'), ('company_id', '=', bank.company_id.id)], context=context)
+ ids = obj_acc.search(cr, uid, [('type','=','liquidity'), ('company_id', '=', bank.company_id.id), ('parent_id', '!=', False)], context=context)
# No liquidity account exists, no template available
if not ids: continue
- ref_acc_bank_temp = obj_acc.browse(cr, uid, ids[0], context=context)
- ref_acc_bank = ref_acc_bank_temp.parent_id
+ ref_acc_bank = obj_acc.browse(cr, uid, ids[0], context=context).parent_id
while True:
new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num)
ids = obj_acc.search(cr, uid, [('code', '=', new_code), ('company_id', '=', bank.company_id.id)])
@@ -82,7 +81,7 @@ class bank(osv.osv):
'name': name,
'code': new_code,
'type': 'liquidity',
- 'user_type': ref_acc_bank_temp.user_type.id,
+ 'user_type': ref_acc_bank.user_type.id,
'reconcile': False,
'parent_id': ref_acc_bank.id,
'company_id': bank.company_id.id,
diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py
index 023765d73f0..8a15321b9c6 100644
--- a/addons/account/account_bank_statement.py
+++ b/addons/account/account_bank_statement.py
@@ -420,7 +420,7 @@ class account_bank_statement(osv.osv):
for st_line in st.line_ids:
if st_line.analytic_account_id:
if not st.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal !'),_("You have to assign an analytic journal on the '%s' journal!") % (st.journal_id.name,))
+ raise osv.except_osv(_('No Analytic Journal!'),_("You have to assign an analytic journal on the '%s' journal!") % (st.journal_id.name,))
if not st_line.amount:
continue
st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context)
diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py
index 40f0ca80738..8e3e250d41c 100644
--- a/addons/account/account_cash_statement.py
+++ b/addons/account/account_cash_statement.py
@@ -252,7 +252,7 @@ class account_cash_statement(osv.osv):
for statement in statement_pool.browse(cr, uid, ids, context=context):
vals = {}
if not self._user_allow(cr, uid, statement.id, context=context):
- raise osv.except_osv(_('Error!'), (_('You do not have rights to open this %s journal !') % (statement.journal_id.name, )))
+ raise osv.except_osv(_('Error!'), (_('You do not have rights to open this %s journal!') % (statement.journal_id.name, )))
if statement.name and statement.name == '/':
c = {'fiscalyear_id': statement.period_id.fiscalyear_id.id}
diff --git a/addons/account/account_financial_report_data.xml b/addons/account/account_financial_report_data.xml
index 6410a5e887c..e8ff33151c3 100644
--- a/addons/account/account_financial_report_data.xml
+++ b/addons/account/account_financial_report_data.xml
@@ -6,16 +6,19 @@
-->
Profit and Loss
+ sumIncome
+ detail_with_hierarchyaccount_typeExpense
+ detail_with_hierarchyaccount_type
diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml
index 58e824a6250..b03babc63ac 100644
--- a/addons/account/account_installer.xml
+++ b/addons/account/account_installer.xml
@@ -20,10 +20,11 @@
+
-
+
-
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index c47cf70b673..87e6a66740c 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -51,9 +51,12 @@ class account_invoice(osv.osv):
company_id = context.get('company_id', user.company_id.id)
type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale_refund', 'in_refund': 'purchase_refund'}
journal_obj = self.pool.get('account.journal')
- res = journal_obj.search(cr, uid, [('type', '=', type2journal.get(type_inv, 'sale')),
- ('company_id', '=', company_id)],
- limit=1)
+ domain = [('company_id', '=', company_id)]
+ if isinstance(type_inv, list):
+ domain.append(('type', 'in', [type2journal.get(type) for type in type_inv if type2journal.get(type)]))
+ else:
+ domain.append(('type', '=', type2journal.get(type_inv, 'sale')))
+ res = journal_obj.search(cr, uid, domain, limit=1)
return res and res[0] or False
def _get_currency(self, cr, uid, context=None):
@@ -69,7 +72,7 @@ class account_invoice(osv.osv):
tt = type2journal.get(type_inv, 'sale')
result = self.pool.get('account.analytic.journal').search(cr, uid, [('type','=',tt)], context=context)
if not result:
- raise osv.except_osv(_('No Analytic Journal !'),_("You must define an analytic journal of type '%s'!") % (tt,))
+ raise osv.except_osv(_('No Analytic Journal!'),_("You must define an analytic journal of type '%s'!") % (tt,))
return result[0]
def _get_type(self, cr, uid, context=None):
@@ -89,13 +92,43 @@ class account_invoice(osv.osv):
return [('none', _('Free Reference'))]
def _amount_residual(self, cr, uid, ids, name, args, context=None):
+ """Function of the field residua. It computes the residual amount (balance) for each invoice"""
+ if context is None:
+ context = {}
+ ctx = context.copy()
result = {}
+ currency_obj = self.pool.get('res.currency')
for invoice in self.browse(cr, uid, ids, context=context):
+ nb_inv_in_partial_rec = max_invoice_id = 0
result[invoice.id] = 0.0
if invoice.move_id:
- for m in invoice.move_id.line_id:
- if m.account_id.type in ('receivable','payable'):
- result[invoice.id] += m.amount_residual_currency
+ for aml in invoice.move_id.line_id:
+ if aml.account_id.type in ('receivable','payable'):
+ if aml.currency_id and aml.currency_id.id == invoice.currency_id.id:
+ result[invoice.id] += aml.amount_residual_currency
+ else:
+ ctx['date'] = aml.date
+ result[invoice.id] += currency_obj.compute(cr, uid, aml.company_id.currency_id.id, invoice.currency_id.id, aml.amount_residual, context=ctx)
+
+ if aml.reconcile_partial_id.line_partial_ids:
+ #we check if the invoice is partially reconciled and if there are other invoices
+ #involved in this partial reconciliation (and we sum these invoices)
+ for line in aml.reconcile_partial_id.line_partial_ids:
+ if line.invoice:
+ nb_inv_in_partial_rec += 1
+ #store the max invoice id as for this invoice we will make a balance instead of a simple division
+ max_invoice_id = max(max_invoice_id, line.invoice.id)
+ if nb_inv_in_partial_rec:
+ #if there are several invoices in a partial reconciliation, we split the residual by the number
+ #of invoice to have a sum of residual amounts that matches the partner balance
+ new_value = currency_obj.round(cr, uid, invoice.currency_id, result[invoice.id] / nb_inv_in_partial_rec)
+ if invoice.id == max_invoice_id:
+ #if it's the last the invoice of the bunch of invoices partially reconciled together, we make a
+ #balance to avoid rounding errors
+ result[invoice.id] = result[invoice.id] - ((nb_inv_in_partial_rec - 1) * new_value)
+ else:
+ result[invoice.id] = new_value
+
#prevent the residual amount on the invoice to be less than 0
result[invoice.id] = max(result[invoice.id], 0.0)
return result
@@ -188,8 +221,8 @@ class account_invoice(osv.osv):
'type': {
},
'state': {
- 'account.mt_invoice_paid': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'paid' and obj['type'] in ('out_invoice', 'out_refund'),
- 'account.mt_invoice_validated': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'open' and obj['type'] in ('out_invoice', 'out_refund'),
+ 'account.mt_invoice_paid': lambda self, cr, uid, obj, ctx=None: obj.state == 'paid' and obj.type in ('out_invoice', 'out_refund'),
+ 'account.mt_invoice_validated': lambda self, cr, uid, obj, ctx=None: obj.state == 'open' and obj.type in ('out_invoice', 'out_refund'),
},
}
_columns = {
@@ -548,6 +581,10 @@ class account_invoice(osv.osv):
return {'value': {}}
def onchange_company_id(self, cr, uid, ids, company_id, part_id, type, invoice_line, currency_id, context=None):
+ #TODO: add the missing context parameter when forward-porting in trunk so we can remove
+ # this hack!
+ context = self.pool['res.users'].context_get(cr, uid)
+
val = {}
dom = {}
obj_journal = self.pool.get('account.journal')
@@ -600,18 +637,17 @@ class account_invoice(osv.osv):
obj_l = account_obj.browse(cr, uid, inv_line[2]['account_id'])
if obj_l.company_id.id != company_id:
raise osv.except_osv(_('Configuration Error!'),
- _('Invoice line account\'s company and invoice\'s compnay does not match.'))
+ _('Invoice line account\'s company and invoice\'s company does not match.'))
else:
continue
if company_id and type:
- if type in ('out_invoice'):
- journal_type = 'sale'
- elif type in ('out_refund'):
- journal_type = 'sale_refund'
- elif type in ('in_refund'):
- journal_type = 'purchase_refund'
- else:
- journal_type = 'purchase'
+ journal_mapping = {
+ 'out_invoice': 'sale',
+ 'out_refund': 'sale_refund',
+ 'in_refund': 'purchase_refund',
+ 'in_invoice': 'purchase',
+ }
+ journal_type = journal_mapping[type]
journal_ids = obj_journal.search(cr, uid, [('company_id','=',company_id), ('type', '=', journal_type)])
if journal_ids:
val['journal_id'] = journal_ids[0]
@@ -621,7 +657,12 @@ class account_invoice(osv.osv):
if r[1] == 'journal_id' and r[2] in journal_ids:
val['journal_id'] = r[2]
if not val.get('journal_id', False):
- raise osv.except_osv(_('Configuration Error!'), (_('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Journals\Journals.') % (journal_type)))
+ journal_type_map = dict(obj_journal._columns['type'].selection)
+ journal_type_label = self.pool['ir.translation']._get_source(cr, uid, None, ('code','selection'),
+ context.get('lang'),
+ journal_type_map.get(journal_type))
+ raise osv.except_osv(_('Configuration Error!'),
+ _('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Journals\Journals.') % ('"%s"' % journal_type_label))
dom = {'journal_id': [('id', 'in', journal_ids)]}
else:
journal_ids = obj_journal.search(cr, uid, [])
@@ -635,6 +676,26 @@ class account_invoice(osv.osv):
self.create_workflow(cr, uid, ids)
return True
+ # ----------------------------------------
+ # Mail related methods
+ # ----------------------------------------
+
+ def _get_formview_action(self, cr, uid, id, context=None):
+ """ Update form view id of action to open the invoice """
+ action = super(account_invoice, self)._get_formview_action(cr, uid, id, context=context)
+ obj = self.browse(cr, uid, id, context=context)
+ if obj.type == 'in_invoice':
+ model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
+ action.update({
+ 'views': [(view_id, 'form')],
+ })
+ else:
+ model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'invoice_form')
+ action.update({
+ 'views': [(view_id, 'form')],
+ })
+ return action
+
# Workflow stuff
#################
@@ -722,7 +783,7 @@ class account_invoice(osv.osv):
inv = self.browse(cr, uid, id)
cur_obj = self.pool.get('res.currency')
- company_currency = inv.company_id.currency_id.id
+ company_currency = self.pool['res.company'].browse(cr, uid, inv.company_id.id).currency_id.id
if inv.type in ('out_invoice', 'in_refund'):
sign = 1
else:
@@ -736,7 +797,7 @@ class account_invoice(osv.osv):
else:
ref = self._convert_ref(cr, uid, inv.number)
if not inv.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,))
+ raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal!") % (inv.journal_id.name,))
il['analytic_lines'] = [(0,0, {
'name': il['name'],
'date': inv['date_invoice'],
@@ -769,6 +830,7 @@ class account_invoice(osv.osv):
return move_lines
def check_tax_lines(self, cr, uid, inv, compute_taxes, ait_obj):
+ company_currency = self.pool['res.company'].browse(cr, uid, inv.company_id.id).currency_id
if not inv.tax_line:
for tax in compute_taxes.values():
ait_obj.create(cr, uid, tax)
@@ -782,7 +844,7 @@ class account_invoice(osv.osv):
if not key in compute_taxes:
raise osv.except_osv(_('Warning!'), _('Global taxes defined, but they are not in invoice lines !'))
base = compute_taxes[key]['base']
- if abs(base - tax.base) > inv.company_id.currency_id.rounding:
+ if abs(base - tax.base) > company_currency.rounding:
raise osv.except_osv(_('Warning!'), _('Tax base different!\nClick on compute to update the tax base.'))
for key in compute_taxes:
if not key in tax_key:
@@ -861,7 +923,7 @@ class account_invoice(osv.osv):
if not inv.journal_id.sequence_id:
raise osv.except_osv(_('Error!'), _('Please define sequence on the journal related to this invoice.'))
if not inv.invoice_line:
- raise osv.except_osv(_('No Invoice Lines !'), _('Please create some invoice lines.'))
+ raise osv.except_osv(_('No Invoice Lines!'), _('Please create some invoice lines.'))
if inv.move_id:
continue
@@ -869,7 +931,7 @@ class account_invoice(osv.osv):
ctx.update({'lang': inv.partner_id.lang})
if not inv.date_invoice:
self.write(cr, uid, [inv.id], {'date_invoice': fields.date.context_today(self,cr,uid,context=context)}, context=ctx)
- company_currency = inv.company_id.currency_id.id
+ company_currency = self.pool['res.company'].browse(cr, uid, inv.company_id.id).currency_id.id
# create the analytical lines
# one move line per invoice line
iml = self._get_analytic_lines(cr, uid, inv.id, context=ctx)
@@ -882,7 +944,7 @@ class account_invoice(osv.osv):
group_check_total = self.pool.get('res.groups').browse(cr, uid, group_check_total_id, context=context)
if group_check_total and uid in [x.id for x in group_check_total.users]:
if (inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0)):
- raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe encoded total does not match the computed total.'))
+ raise osv.except_osv(_('Bad Total!'), _('Please verify the price of the invoice!\nThe encoded total does not match the computed total.'))
if inv.payment_term:
total_fixed = total_percent = 0
@@ -917,7 +979,7 @@ class account_invoice(osv.osv):
total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml, context=ctx)
acc_id = inv.account_id.id
- name = inv['name'] or '/'
+ name = inv['name'] or inv['supplier_invoice_number'] or '/'
totlines = False
if inv.payment_term:
totlines = payment_term_obj.compute(cr,
@@ -985,7 +1047,8 @@ class account_invoice(osv.osv):
'line_id': line,
'journal_id': journal_id,
'date': date,
- 'narration':inv.comment
+ 'narration': inv.comment,
+ 'company_id': inv.company_id.id,
}
period_id = inv.period_id and inv.period_id.id or False
ctx.update(company_id=inv.company_id.id)
@@ -1115,12 +1178,12 @@ class account_invoice(osv.osv):
if not ids:
return []
types = {
- 'out_invoice': 'Invoice ',
- 'in_invoice': 'Sup. Invoice ',
- 'out_refund': 'Refund ',
- 'in_refund': 'Supplier Refund ',
+ 'out_invoice': _('Invoice'),
+ 'in_invoice': _('Supplier Invoice'),
+ 'out_refund': _('Refund'),
+ 'in_refund': _('Supplier Refund'),
}
- return [(r['id'], (r['number']) or types[r['type']] + (r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
+ return [(r['id'], '%s %s' % (r['number'] or types[r['type']], r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
if not args:
@@ -1423,7 +1486,7 @@ class account_invoice_line(osv.osv):
context = dict(context)
context.update({'company_id': company_id, 'force_company': company_id})
if not partner_id:
- raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") )
+ raise osv.except_osv(_('No Partner Defined!'),_("You must first select a partner!") )
if not product:
if type in ('in_invoice', 'in_refund'):
return {'value': {}, 'domain':{'product_uom':[]}}
@@ -1438,6 +1501,7 @@ class account_invoice_line(osv.osv):
result = {}
res = self.pool.get('product.product').browse(cr, uid, product, context=context)
+ result['name'] = res.partner_ref
if type in ('out_invoice','out_refund'):
a = res.property_account_income.id
if not a:
@@ -1452,19 +1516,21 @@ class account_invoice_line(osv.osv):
if type in ('out_invoice', 'out_refund'):
taxes = res.taxes_id and res.taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False)
+ if res.description_sale:
+ result['name'] += '\n'+res.description_sale
else:
taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False)
+ if res.description_purchase:
+ result['name'] += '\n'+res.description_purchase
+
tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
if type in ('in_invoice', 'in_refund'):
result.update( {'price_unit': price_unit or res.standard_price,'invoice_line_tax_id': tax_id} )
else:
result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
- result['name'] = res.partner_ref
result['uos_id'] = uom_id or res.uom_id.id
- if res.description:
- result['name'] += '\n'+res.description
domain = {'uos_id':[('category_id','=',res.uom_id.category_id.id)]}
@@ -1517,8 +1583,7 @@ class account_invoice_line(osv.osv):
if context is None:
context = {}
inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
- company_currency = inv.company_id.currency_id.id
-
+ company_currency = self.pool['res.company'].browse(cr, uid, inv.company_id.id).currency_id.id
for line in inv.invoice_line:
mres = self.move_line_get_item(cr, uid, line, context)
if not mres:
@@ -1662,8 +1727,7 @@ class account_invoice_tax(osv.osv):
cur_obj = self.pool.get('res.currency')
inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
cur = inv.currency_id
- company_currency = inv.company_id.currency_id.id
-
+ company_currency = self.pool['res.company'].browse(cr, uid, inv.company_id.id).currency_id.id
for line in inv.invoice_line:
for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, line.product_id, inv.partner_id)['taxes']:
val={}
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 7469c38decb..c71b97d5796 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -197,7 +197,7 @@
@@ -320,7 +320,7 @@
@@ -353,7 +353,7 @@
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
index 006e2c55f5f..314e3423996 100644
--- a/addons/account/account_move_line.py
+++ b/addons/account/account_move_line.py
@@ -192,7 +192,7 @@ class account_move_line(osv.osv):
for obj_line in self.browse(cr, uid, ids, context=context):
if obj_line.analytic_account_id:
if not obj_line.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (obj_line.journal_id.name, ))
+ raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal!") % (obj_line.journal_id.name, ))
vals_line = self._prepare_analytic_line(cr, uid, obj_line, context=context)
acc_ana_line_obj.create(cr, uid, vals_line)
return True
@@ -626,7 +626,7 @@ class account_move_line(osv.osv):
(_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']),
(_check_currency, 'The selected account of your Journal Entry forces to provide a secondary currency. You should remove the secondary currency on the account or select a multi-currency view on the journal.', ['currency_id']),
(_check_currency_and_amount, "You cannot create journal items with a secondary currency without recording both 'currency' and 'amount currency' field.", ['currency_id','amount_currency']),
- (_check_currency_amount, 'The amount expressed in the secondary currency must be positif when journal item are debit and negatif when journal item are credit.', ['amount_currency']),
+ (_check_currency_amount, 'The amount expressed in the secondary currency must be positive when the journal item is a debit and negative when if it is a credit.', ['amount_currency']),
(_check_currency_company, "You cannot provide a secondary currency if it is the same than the company one." , ['currency_id']),
]
@@ -1066,12 +1066,12 @@ class account_move_line(osv.osv):
for line in self.browse(cr, uid, ids, context=context):
ctx = context.copy()
- if ('journal_id' not in ctx):
+ if not ctx.get('journal_id'):
if line.move_id:
ctx['journal_id'] = line.move_id.journal_id.id
else:
ctx['journal_id'] = line.journal_id.id
- if ('period_id' not in ctx):
+ if not ctx.get('period_id'):
if line.move_id:
ctx['period_id'] = line.move_id.period_id.id
else:
@@ -1101,7 +1101,7 @@ class account_move_line(osv.osv):
period = period_obj.browse(cr, uid, period_id, context=context)
for (state,) in result:
if state == 'done':
- raise osv.except_osv(_('Error !'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
+ raise osv.except_osv(_('Error!'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
if not result:
jour_period_obj.create(cr, uid, {
'name': (journal.code or journal.name)+':'+(period.name or ''),
@@ -1181,7 +1181,7 @@ class account_move_line(osv.osv):
move_id = move_obj.create(cr, uid, v, context)
vals['move_id'] = move_id
else:
- raise osv.except_osv(_('No piece number !'), _('Cannot create an automatic sequence for this piece.\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.'))
+ raise osv.except_osv(_('No Piece Number!'), _('Cannot create an automatic sequence for this piece.\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.'))
ok = not (journal.type_control_ids or journal.account_control_ids)
if ('account_id' in vals):
account = account_obj.browse(cr, uid, vals['account_id'], context=context)
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index 13bc694a1cc..758385d66cb 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -585,7 +585,10 @@
-
+
@@ -907,9 +910,7 @@
- [[ data['form']['direction_selection'] == 'future' and 'Due' or 'Not due' ]]
+ Due[[ data['form']['direction_selection'] == 'future' and ' ' or removeParentNode('para') ]]
+ Not due[[ data['form']['direction_selection'] != 'future' and ' ' or removeParentNode('para') ]]
[[ data['model']=='account.account' and 'Company'or removeParentNode('para') ]]
- [[ data['model']=='ir.ui.menu' and 'Chart of Accounts' or removeParentNode('para') ]]
+
+ Company[[ data['model']=='account.account' and ' ' or removeParentNode('para') ]]
+ Chart of Accounts[[ data['model']=='ir.ui.menu' and ' ' or removeParentNode('para') ]]
+
Fiscal Year
@@ -233,7 +235,11 @@
[[ get_fiscalyear(data) or '' ]]
-
[[ (data['form']['display_account']=='all' and 'All') or (data['form']['display_account']=='movement' and 'With movements') or 'With balance is not equal to 0']]
+
+ All[[ data['form']['display_account']=='all' and ' ' or removeParentNode('para') ]]
+ With movements[[ data['form']['display_account']=='movement' and ' ' or removeParentNode('para') ]]
+ With balance is not equal to 0[[ data['form']['display_account']=='not_zero' and ' ' or removeParentNode('para') ]]
+
[[ data['form']['filter']=='filter_no' and get_filter(data) or removeParentNode('para') ]] [[ data['form']['filter']=='filter_date' or removeParentNode('blockTable') ]]
[[ data['model']=='account.journal.period' and 'Company' or removeParentNode('para') ]]
- [[ data['model']=='ir.ui.menu' and 'Chart of Accounts' or removeParentNode('para') ]]
+
Company[[ data['model']=='account.journal.period' and ' ' or removeParentNode('para') ]]
+ Chart of Accounts[[ data['model']=='ir.ui.menu' and ' ' or removeParentNode('para') ]]
Fiscal Year
Journals
Filter By [[ data['form']['filter']!='filter_no' and get_filter(data) ]]
diff --git a/addons/account/report/account_general_ledger.py b/addons/account/report/account_general_ledger.py
index 498cb1369a8..4f712ad58cc 100644
--- a/addons/account/report/account_general_ledger.py
+++ b/addons/account/report/account_general_ledger.py
@@ -23,7 +23,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/addons/account/report/account_general_ledger_landscape.rml b/addons/account/report/account_general_ledger_landscape.rml
index 7ae5db98f20..c5d24343148 100644
--- a/addons/account/report/account_general_ledger_landscape.rml
+++ b/addons/account/report/account_general_ledger_landscape.rml
@@ -360,9 +360,8 @@
- [[ data['model']=='account.account' and 'Company' or removeParentNode('para') ]]
- [[ data['model']=='ir.ui.menu' and 'Chart of Accounts' or removeParentNode('para') ]]
-
+ Company[[ data['model']=='account.account' and ' ' or removeParentNode('para') ]]
+ Chart of Accounts[[ data['model']=='ir.ui.menu' and ' ' or removeParentNode('para') ]]
Fiscal Year
@@ -395,7 +394,9 @@
[[', '.join([ lt or '' for lt in get_journal(data) ]) ]]
- [[ (data['form']['display_account']=='all' and 'All') or (data['form']['display_account']=='movement' and 'With movements') or 'With balance is not equal to 0']]
+ All[[ data['form']['display_account']=='all' and ' ' or removeParentNode('para') ]]
+ With movements[[ data['form']['display_account']=='movement' and ' ' or removeParentNode('para') ]]
+ With balance is not equal to 0[[ data['form']['display_account']=='not_zero' and ' ' or removeParentNode('para') ]]
[[ data['form']['filter']=='filter_no' and get_filter(data) or removeParentNode('para') ]]
diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py
index 799b9b1c9fb..d8dc45f9a3b 100644
--- a/addons/account/report/account_invoice_report.py
+++ b/addons/account/report/account_invoice_report.py
@@ -99,12 +99,13 @@ class account_invoice_report(osv.osv):
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',readonly=True),
'residual': fields.float('Total Residual', readonly=True),
'user_currency_residual': fields.function(_compute_amounts_in_user_currency, string="Total Residual", type='float', digits_compute=dp.get_precision('Account'), multi="_compute_amounts"),
+ 'country_id': fields.many2one('res.country', 'Country of the Partner Company'),
}
_order = 'date desc'
def _select(self):
select_str = """
- SELECT sub.id, sub.date, sub.year, sub.month, sub.day, sub.product_id, sub.partner_id,
+ SELECT sub.id, sub.date, sub.year, sub.month, sub.day, sub.product_id, sub.partner_id, sub.country_id,
sub.payment_term, sub.period_id, sub.uom_name, sub.currency_id, sub.journal_id,
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,
@@ -172,7 +173,8 @@ class account_invoice_report(osv.osv):
WHERE a.id = ai.id)
ELSE 1::bigint
END::numeric AS residual,
- ai.commercial_partner_id as commercial_partner_id
+ ai.commercial_partner_id as commercial_partner_id,
+ partner.country_id
"""
return select_str
@@ -180,6 +182,7 @@ class account_invoice_report(osv.osv):
from_str = """
FROM account_invoice_line ail
JOIN account_invoice ai ON ai.id = ail.invoice_id
+ JOIN res_partner partner ON ai.commercial_partner_id = partner.id
LEFT JOIN product_product pr ON pr.id = ail.product_id
left JOIN product_template pt ON pt.id = pr.product_tmpl_id
LEFT JOIN product_uom u ON u.id = ail.uos_id
@@ -195,7 +198,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.commercial_partner_id
+ ai.amount_total, u.uom_type, u.category_id, ai.commercial_partner_id, partner.country_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 96dc948b09a..5f38db5e71f 100644
--- a/addons/account/report/account_invoice_report_view.xml
+++ b/addons/account/report/account_invoice_report_view.xml
@@ -15,6 +15,7 @@
+
@@ -68,6 +69,7 @@
+
diff --git a/addons/account/report/account_journal.py b/addons/account/report/account_journal.py
index 769a8335f55..97e19be4b0c 100644
--- a/addons/account/report/account_journal.py
+++ b/addons/account/report/account_journal.py
@@ -189,11 +189,12 @@ class journal_print(report_sxw.rml_parse, common_report_header):
return data['form']['amount_currency']
def _get_sortby(self, data):
+ # TODO: deprecated, to remove in trunk
if self.sort_selection == 'date':
- return 'Date'
+ return self._translate('Date')
elif self.sort_selection == 'ref':
- return 'Reference Number'
- return 'Date'
+ return self._translate('Reference Number')
+ return self._translate('Date')
report_sxw.report_sxw('report.account.journal.period.print', 'account.journal.period', 'addons/account/report/account_journal.rml', parser=journal_print, header='external')
report_sxw.report_sxw('report.account.journal.period.print.sale.purchase', 'account.journal.period', 'addons/account/report/account_journal_sale_purchase.rml', parser=journal_print, header='external')
diff --git a/addons/account/report/account_journal.rml b/addons/account/report/account_journal.rml
index fb203d4e664..6d606ed1937 100644
--- a/addons/account/report/account_journal.rml
+++ b/addons/account/report/account_journal.rml
@@ -186,8 +186,8 @@
-
[[ data['model']=='account.journal.period'and 'Company' or removeParentNode('para') ]]
- [[ data['model']=='ir.ui.menu' and 'Chart of Accounts' or removeParentNode('para') ]]
+
Company[[ data['model']=='account.journal.period'and ' ' or removeParentNode('para') ]]
+ Chart of Accounts[[ data['model']=='ir.ui.menu' and ' ' or removeParentNode('para') ]]
Fiscal Year
Journal
Period
@@ -199,8 +199,10 @@
[[ get_fiscalyear(data) or '' ]]
[[ o.journal_id.name ]]
[[ o.period_id.name ]]
-
[[ get_sortby(data) ]]
-
[[ get_target_move(data) ]]
+
+ Date[[ data['form'].get('sort_selection', 'date') == 'date' and ' ' or removeParentNode('para') ]]
+ Reference Number[[ data['form'].get('sort_selection', 'date') == 'ref' and ' ' or removeParentNode('para') ]]
+
+By far the most beautiful and full featured accounting software. OpenERP Accounting allows a better way to collaborate with your accountants, your customers and control your suppliers.
+
+Activate features on demand, from integrated analytic accounting to budget, assets and multiple companies consolidation.
+
+Record transactions in a few clicks and easily manage all financial activities
+in one place. OpenERP's user interface is designed with productivity in mind.
+
+
+
+
+
+
+
+
+
+
+
+
A Better Way To Work – Together
+
+
+
+
+
+Share access to your latest business numbers with your team and your accountant – so everyone is up to speed. From work, home or on the go.
+
+
+
+
+
+
+
+
Connect Your Bank Accounts
+
+
+Import your bank statements and reconcile them in just a few clicks. Prepare payment orders based on your supplier invoices and payment terms.
+
+
+
+
+
+
+
+
+
+
+
Get Paid Faster
+
Electronic invoicing and automated follow-ups
+
+
+
+
+
+
+Create and send professional invoices & get paid online. Get rid of the stress of having to constantly remind your debtors. Simply set-up and automate follow-ups to get paid quickly.
+
+
+
+
+
+
+
+
Sales Integration
+
+
+Automatically create invoices from sales orders, delivery orders or base them on time and material. Re-invoice expenses on projects to your customer in just a few clicks.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Purchase Integration
+
+Control supplier invocies based on purchase orders. Get real-time inventory valuation reports automatically posted in your accounts.
+
+
+
+
+
+
+
+
Multi-Level Analytic Accounting
+
+
+Integrate your analytic accounting operations with timesheets, projects, invoices, expenses, etc. No need to record transactions, all analytic entries are posted automatically following your business rules.
+
+
+
+
+
+
+
+
+
+
+
+
Everything you need to grow
+
+
+
+
+
+Manage your assets, track expenses, control budgets, multi-level analytic accounting; OpenERP has all the features you need to sustain all your business activities.
+
+
+
+
+
+
+
+
+
Scale With Your Organization
+
Used by very small to very large organizations
+
+
+OpenERP supports multiple currencies, multiple users with different access rights, multiple companies with real time consolidation and unlimited analytic plans.
+
+
+
+
+
+
+
+
+
+
+
Dashboard & KPIs
+
+
+
+
+
+Get direct access to key information with dynamic and customizable dashboards. Analyse your financial activities with the drill-up, drill-down, drill-across and filter features.
+
+
+
+
+
+
+
+
Many companies already enjoy it
+
Hear what they have to say !
+
+
+
+
+ OpenERP Accounting is a great way to record all business transactions
+ right when they happen. Awesome and cost-effective!
+
+
+
\n"
+" From this report, you can have an overview on all depreciation. "
+"The\n"
+" tool search can also be used to personalise your Assets reports "
+"and\n"
+" so, match this analysis to your needs;\n"
+"
A budget is a forecast of your company's income and/or expenses
expected for a period in the future. A budget is defined on some
financial accounts and/or analytic accounts (that may represent
diff --git a/addons/account_cancel/i18n/th.po b/addons/account_cancel/i18n/th.po
new file mode 100644
index 00000000000..eabcc0814dd
--- /dev/null
+++ b/addons/account_cancel/i18n/th.po
@@ -0,0 +1,23 @@
+# Thai 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-15 07:04+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Thai
\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-16 05:12+0000\n"
+"X-Generator: Launchpad (build 16626)\n"
+
+#. module: account_cancel
+#: view:account.invoice:0
+msgid "Cancel"
+msgstr ""
diff --git a/addons/account_cancel/i18n/vi.po b/addons/account_cancel/i18n/vi.po
index 8198e802022..89a7feb7942 100644
--- a/addons/account_cancel/i18n/vi.po
+++ b/addons/account_cancel/i18n/vi.po
@@ -8,19 +8,19 @@ 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: 2010-12-21 14:22+0000\n"
-"Last-Translator: OpenERP Administrators \n"
+"PO-Revision-Date: 2013-06-30 16:08+0000\n"
+"Last-Translator: Hung Tran \n"
"Language-Team: Vietnamese \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:42+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-07-01 05:14+0000\n"
+"X-Generator: Launchpad (build 16692)\n"
#. module: account_cancel
#: view:account.invoice:0
msgid "Cancel"
-msgstr ""
+msgstr "Hủy bỏ"
#~ msgid "Account Cancel"
#~ msgstr "Hủy bỏ Tài khoản"
diff --git a/addons/account_check_writing/i18n/ru.po b/addons/account_check_writing/i18n/ru.po
index ba474c72a22..8e68dd7152a 100644
--- a/addons/account_check_writing/i18n/ru.po
+++ b/addons/account_check_writing/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-12-11 13:00+0000\n"
-"Last-Translator: FULL NAME \n"
+"PO-Revision-Date: 2013-06-03 07:47+0000\n"
+"Last-Translator: Chertykov Denis \n"
"Language-Team: Russian \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:51+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-04 05:20+0000\n"
+"X-Generator: Launchpad (build 16660)\n"
#. module: account_check_writing
#: selection:res.company,check_layout:0
@@ -25,13 +25,13 @@ msgstr ""
#. module: account_check_writing
#: report:account.print.check.top:0
msgid "Open Balance"
-msgstr ""
+msgstr "Открытый баланс"
#. module: account_check_writing
#: view:account.check.write:0
#: view:account.voucher:0
msgid "Print Check"
-msgstr ""
+msgstr "Напечатать чек"
#. module: account_check_writing
#: selection:res.company,check_layout:0
@@ -82,7 +82,7 @@ msgstr "Описание"
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_account_journal
msgid "Journal"
-msgstr ""
+msgstr "Журнал"
#. module: account_check_writing
#: model:ir.actions.act_window,name:account_check_writing.action_write_check
@@ -95,14 +95,14 @@ msgstr ""
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Discount"
-msgstr ""
+msgstr "Скидка"
#. module: account_check_writing
#: report:account.print.check.bottom:0
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Original Amount"
-msgstr ""
+msgstr "Первоначальная сумма"
#. module: account_check_writing
#: field:res.company,check_layout:0
@@ -119,7 +119,7 @@ msgstr ""
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Payment"
-msgstr ""
+msgstr "Платеж"
#. module: account_check_writing
#: field:account.journal,use_preprint_check:0
@@ -153,7 +153,7 @@ msgstr ""
#: report:account.print.check.middle:0
#: report:account.print.check.top:0
msgid "Due Date"
-msgstr ""
+msgstr "Дата исполнения"
#. module: account_check_writing
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_middle
@@ -163,13 +163,13 @@ msgstr ""
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_res_company
msgid "Companies"
-msgstr ""
+msgstr "Компании"
#. module: account_check_writing
#: code:addons/account_check_writing/wizard/account_check_batch_printing.py:59
#, python-format
msgid "Error!"
-msgstr ""
+msgstr "Ошибка!"
#. module: account_check_writing
#: help:account.check.write,check_number:0
@@ -202,12 +202,12 @@ msgstr ""
#. module: account_check_writing
#: view:account.check.write:0
msgid "or"
-msgstr ""
+msgstr "или"
#. module: account_check_writing
#: field:account.voucher,amount_in_word:0
msgid "Amount in Word"
-msgstr ""
+msgstr "Сумма прописью"
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_account_check_write
@@ -217,7 +217,7 @@ msgstr ""
#. module: account_check_writing
#: view:account.check.write:0
msgid "Cancel"
-msgstr ""
+msgstr "Отмена"
#. module: account_check_writing
#: field:account.check.write,check_number:0
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index 036feaaf0e5..715860cab83 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -165,9 +165,8 @@ class res_partner(osv.osv):
else:
action_text = partner.latest_followup_level_id_without_lit.manual_action_note or ''
- #Check date: put the minimum date if it existed already
- action_date = (partner.payment_next_action_date and min(partner.payment_next_action_date, fields.date.context_today(self, cr, uid, context=context))
- ) or fields.date.context_today(self, cr, uid, context=context)
+ #Check date: only change when it did not exist already
+ action_date = partner.payment_next_action_date or fields.date.context_today(self, cr, uid, context=context)
# Check responsible: if partner has not got a responsible already, take from follow-up
responsible_id = False
diff --git a/addons/account_followup/account_followup_customers.xml b/addons/account_followup/account_followup_customers.xml
index 6893abe012e..fba0bce460b 100644
--- a/addons/account_followup/account_followup_customers.xml
+++ b/addons/account_followup/account_followup_customers.xml
@@ -9,11 +9,12 @@
res.partner
-
+
+
@@ -97,7 +98,7 @@
+ groups="account.group_account_user"/>
diff --git a/addons/account_followup/i18n/ru.po b/addons/account_followup/i18n/ru.po
index f6cb2cf0412..b57c8e4315e 100644
--- a/addons/account_followup/i18n/ru.po
+++ b/addons/account_followup/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2011-11-11 15:21+0000\n"
-"Last-Translator: Fabien (Open ERP) \n"
+"PO-Revision-Date: 2013-05-31 10:28+0000\n"
+"Last-Translator: Chertykov Denis \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:11+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-01 05:16+0000\n"
+"X-Generator: Launchpad (build 16660)\n"
#. module: account_followup
#: model:email.template,subject:account_followup.email_template_account_followup_default
@@ -22,7 +22,7 @@ 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} напоминание о платеже"
#. module: account_followup
#: help:res.partner,latest_followup_level_id:0
@@ -43,12 +43,12 @@ msgstr "Дальнейшие действия"
#. 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 "Дата следующего действия"
#. module: account_followup
#: view:account_followup.followup.line:0
@@ -64,7 +64,7 @@ msgstr ""
#. module: account_followup
#: view:res.partner:0
msgid "⇾ Mark as Done"
-msgstr ""
+msgstr "⇾ отметить как сделанное"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_note:0
@@ -94,7 +94,7 @@ msgstr "Тема эл.письма"
#. 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
@@ -109,19 +109,19 @@ msgstr ""
#. module: account_followup
#: field:account_followup.print,email_body:0
msgid "Email Body"
-msgstr ""
+msgstr "Тело эл. письма"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_account_followup_print
msgid "Send Follow-Ups"
-msgstr ""
+msgstr "Послать напоминания"
#. module: account_followup
#: report:account_followup.followup.print:0
#: code:addons/account_followup/account_followup.py:263
#, python-format
msgid "Amount"
-msgstr ""
+msgstr "Сумма"
#. module: account_followup
#: help:res.partner,payment_next_action:0
@@ -133,7 +133,7 @@ msgstr ""
#. module: account_followup
#: view:res.partner:0
msgid "No Responsible"
-msgstr ""
+msgstr "Нет ответственного"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line2
@@ -209,17 +209,17 @@ msgstr "Всего по дебету"
#. module: account_followup
#: field:res.partner,payment_next_action:0
msgid "Next Action"
-msgstr ""
+msgstr "Следующее действие"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": Partner Name"
-msgstr ""
+msgstr ": Название партнера"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_responsible_id:0
msgid "Assign a Responsible"
-msgstr ""
+msgstr "Назначить ответственного"
#. module: account_followup
#: view:account_followup.followup:0
@@ -305,7 +305,7 @@ msgstr ""
#. 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
@@ -377,7 +377,7 @@ msgstr "Определяет порядок вывода списка напом
#: code:addons/account_followup/wizard/account_followup_print.py:166
#, python-format
msgid " will be sent"
-msgstr ""
+msgstr " будет отправлен"
#. module: account_followup
#: view:account_followup.followup.line:0
@@ -388,7 +388,7 @@ msgstr ""
#: view:account_followup.followup.line:0
#: field:account_followup.followup.line,send_letter:0
msgid "Send a Letter"
-msgstr ""
+msgstr "Отправить письмо"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_account_followup_definition_form
@@ -466,7 +466,7 @@ msgstr "Напечатанное сообщение"
#: code:addons/account_followup/wizard/account_followup_print.py:155
#, python-format
msgid "Anybody"
-msgstr ""
+msgstr "Кто угодно"
#. module: account_followup
#: help:account_followup.followup.line,send_email:0
@@ -528,7 +528,7 @@ msgstr ""
#. module: account_followup
#: view:res.partner:0
msgid "Search Partner"
-msgstr ""
+msgstr "Поиск партнера"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.account_followup_print_menu
@@ -554,7 +554,7 @@ msgstr ""
#. module: account_followup
#: view:account_followup.print:0
msgid "or"
-msgstr ""
+msgstr "или"
#. module: account_followup
#: view:res.partner:0
diff --git a/addons/account_followup/report/account_followup_report.xml b/addons/account_followup/report/account_followup_report.xml
index 6fee6a77ac1..b7c38e89f5e 100644
--- a/addons/account_followup/report/account_followup_report.xml
+++ b/addons/account_followup/report/account_followup_report.xml
@@ -6,7 +6,7 @@
account_followup.stat.treeaccount_followup.stat
-
+
diff --git a/addons/account_followup/security/account_followup_security.xml b/addons/account_followup/security/account_followup_security.xml
index 1586403d701..69c9a44a1b9 100644
--- a/addons/account_followup/security/account_followup_security.xml
+++ b/addons/account_followup/security/account_followup_security.xml
@@ -4,7 +4,7 @@
Account Follow-up multi company rule
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
diff --git a/addons/account_followup/security/ir.model.access.csv b/addons/account_followup/security/ir.model.access.csv
index 8774015efc6..591cc347563 100644
--- a/addons/account_followup/security/ir.model.access.csv
+++ b/addons/account_followup/security/ir.model.access.csv
@@ -3,5 +3,5 @@ access_account_followup_followup_line,account_followup.followup.line,model_accou
access_account_followup_followup_line_manager,account_followup.followup.line.manager,model_account_followup_followup_line,account.group_account_manager,1,1,1,1
access_account_followup_followup_accountant,account_followup.followup user,model_account_followup_followup,account.group_account_invoice,1,0,0,0
access_account_followup_followup_manager,account_followup.followup.manager,model_account_followup_followup,account.group_account_manager,1,1,1,1
-access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,1,1
-access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_user,1,1,1,1
+access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,0,0
+access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_user,1,1,0,0
diff --git a/addons/account_payment/security/account_payment_security.xml b/addons/account_payment/security/account_payment_security.xml
index 4bca00eaa6d..fbe29699e86 100644
--- a/addons/account_payment/security/account_payment_security.xml
+++ b/addons/account_payment/security/account_payment_security.xml
@@ -15,21 +15,21 @@
Payment Mode company rule
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]Payment order multi company rule
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]Payment line multi company rule
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
diff --git a/addons/account_payment/wizard/account_payment_order.py b/addons/account_payment/wizard/account_payment_order.py
index 08d36c45eff..de9c47ec005 100644
--- a/addons/account_payment/wizard/account_payment_order.py
+++ b/addons/account_payment/wizard/account_payment_order.py
@@ -23,6 +23,7 @@ import time
from lxml import etree
from openerp.osv import fields, osv
+from openerp.tools.translate import _
class payment_order_create(osv.osv_memory):
"""
@@ -87,6 +88,7 @@ class payment_order_create(osv.osv_memory):
'order_id': payment.id,
'partner_id': line.partner_id and line.partner_id.id or False,
'communication': line.ref or '/',
+ 'state': line.invoice and line.invoice.reference_type != 'none' and 'structured' or 'normal',
'date': date_to_pay,
'currency': (line.invoice and line.invoice.currency_id.id) or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,
}, context=context)
@@ -108,7 +110,7 @@ class payment_order_create(osv.osv_memory):
context.update({'line_ids': line_ids})
model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'view_create_payment_order_lines')], context=context)
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
- return {'name': ('Entrie Lines'),
+ return {'name': _('Entry Lines'),
'context': context,
'view_type': 'form',
'view_mode': 'form',
diff --git a/addons/account_test/account_test.py b/addons/account_test/account_test.py
index 98e27380837..cc60108bf20 100644
--- a/addons/account_test/account_test.py
+++ b/addons/account_test/account_test.py
@@ -24,7 +24,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/addons/account_test/i18n/ru.po b/addons/account_test/i18n/ru.po
new file mode 100644
index 00000000000..d36d83d2e99
--- /dev/null
+++ b/addons/account_test/i18n/ru.po
@@ -0,0 +1,241 @@
+# Russian 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-06-05 07:09+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Russian \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-06 05:21+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid ""
+"Code should always set a variable named `result` with the result of your "
+"test, that can be a list or\n"
+"a dictionary. If `result` is an empty list, it means that the test was "
+"succesful. Otherwise it will\n"
+"try to translate and print what is inside `result`.\n"
+"\n"
+"If the result of your test is a dictionary, you can set a variable named "
+"`column_order` to choose in\n"
+"what order you want to print `result`'s content.\n"
+"\n"
+"Should you need them, you can also use the following variables into your "
+"code:\n"
+" * cr: cursor to the database\n"
+" * uid: ID of the current user\n"
+"\n"
+"In any ways, the code must be legal python statements with correct "
+"indentation (if needed).\n"
+"\n"
+"Example: \n"
+" sql = '''SELECT id, name, ref, date\n"
+" FROM account_move_line \n"
+" WHERE account_id IN (SELECT id FROM account_account WHERE type "
+"= 'view')\n"
+" '''\n"
+" cr.execute(sql)\n"
+" result = cr.dictfetchall()"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_02
+msgid "Test 2: Opening a fiscal year"
+msgstr "Проверка 2: Открытие фискального года"
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_05
+msgid ""
+"Check that reconciled invoice for Sales/Purchases has reconciled entries for "
+"Payable and Receivable Accounts"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_03
+msgid ""
+"Check if movement lines are balanced and have the same date and period"
+msgstr ""
+
+#. module: account_test
+#: field:accounting.assert.test,name:0
+msgid "Test Name"
+msgstr ""
+
+#. module: account_test
+#: report:account.test.assert.print:0
+msgid "Accouting tests on"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_01
+msgid "Test 1: General balance"
+msgstr "Проверка 1: Общий баланс"
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_06
+msgid "Check that paid/reconciled invoices are not in 'Open' state"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_05_2
+msgid ""
+"Check that reconciled account moves, that define Payable and Receivable "
+"accounts, are belonging to reconciled invoices"
+msgstr ""
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid "Tests"
+msgstr "Проверки"
+
+#. module: account_test
+#: field:accounting.assert.test,desc:0
+msgid "Test Description"
+msgstr "Описание проверки"
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid "Description"
+msgstr "Описание"
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_06_1
+msgid "Check that there's no move for any account with « View » account type"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_08
+msgid "Test 9 : Accounts and partners on account moves"
+msgstr ""
+
+#. module: account_test
+#: model:ir.actions.act_window,name:account_test.action_accounting_assert
+#: model:ir.actions.report.xml,name:account_test.account_assert_test_report
+#: model:ir.ui.menu,name:account_test.menu_action_license
+msgid "Accounting Tests"
+msgstr ""
+
+#. module: account_test
+#: code:addons/account_test/report/account_test_report.py:74
+#, python-format
+msgid "The test was passed successfully"
+msgstr "Проверка прошла успешно"
+
+#. module: account_test
+#: field:accounting.assert.test,active:0
+msgid "Active"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_06
+msgid "Test 6 : Invoices status"
+msgstr ""
+
+#. module: account_test
+#: model:ir.model,name:account_test.model_accounting_assert_test
+msgid "accounting.assert.test"
+msgstr "accounting.assert.test"
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_05
+msgid ""
+"Test 5.1 : Payable and Receivable accountant lines of reconciled invoices"
+msgstr ""
+
+#. module: account_test
+#: field:accounting.assert.test,code_exec:0
+msgid "Python code"
+msgstr "Код на Python"
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_07
+msgid ""
+"Check on bank statement that the Closing Balance = Starting Balance + sum of "
+"statement lines"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_07
+msgid "Test 8 : Closing balance on bank statements"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_03
+msgid "Test 3: Movement lines"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_05_2
+msgid "Test 5.2 : Reconcilied invoices and Payable/Receivable accounts"
+msgstr ""
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid "Expression"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_04
+msgid "Test 4: Totally reconciled mouvements"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_04
+msgid "Check if the totally reconciled movements are balanced"
+msgstr ""
+
+#. module: account_test
+#: field:accounting.assert.test,sequence:0
+msgid "Sequence"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_02
+msgid ""
+"Check if the balance of the new opened fiscal year matches with last year's "
+"balance"
+msgstr ""
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid "Python Code"
+msgstr "Код на Python"
+
+#. module: account_test
+#: model:ir.actions.act_window,help:account_test.action_accounting_assert
+msgid ""
+"
\n"
+" Click to create Accounting Test.\n"
+"
\n"
+" "
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_01
+msgid "Check the balance: Debit sum = Credit sum"
+msgstr "Проверяет баланс: сумма дебита = сумма кредита"
+
+#. module: account_test
+#: model:accounting.assert.test,desc:account_test.account_test_08
+msgid "Check that general accounts and partners on account moves are active"
+msgstr ""
+
+#. module: account_test
+#: model:accounting.assert.test,name:account_test.account_test_06_1
+msgid "Test 7: « View » account type"
+msgstr ""
+
+#. module: account_test
+#: view:accounting.assert.test:0
+msgid "Code Help"
+msgstr ""
diff --git a/addons/account_voucher/__openerp__.py b/addons/account_voucher/__openerp__.py
index 345c3378aa0..a043b15a518 100644
--- a/addons/account_voucher/__openerp__.py
+++ b/addons/account_voucher/__openerp__.py
@@ -67,6 +67,7 @@ This module manages:
'test/sales_payment.yml',
'test/account_voucher_report.yml',
'test/case1_usd_usd.yml',
+ 'test/case1_usd_usd_payment_rate.yml',
'test/case2_usd_eur_debtor_in_eur.yml',
'test/case2_usd_eur_debtor_in_usd.yml',
'test/case3_eur_eur.yml',
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index b176c3b8fd9..81eb76ff3a8 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -26,6 +26,19 @@ from openerp.osv import fields, osv
import openerp.addons.decimal_precision as dp
from openerp.tools.translate import _
from openerp.tools import float_compare
+from openerp.report import report_sxw
+
+class res_currency(osv.osv):
+ _inherit = "res.currency"
+
+ def _get_current_rate(self, cr, uid, ids, name, arg, context=None):
+ if context is None:
+ context = {}
+ res = super(res_currency, self)._get_current_rate(cr, uid, ids, name, arg, context=context)
+ if context.get('voucher_special_currency') in ids and context.get('voucher_special_currency_rate'):
+ res[context.get('voucher_special_currency')] = context.get('voucher_special_currency_rate')
+ return res
+
class res_company(osv.osv):
_inherit = "res.company"
@@ -153,7 +166,7 @@ class account_voucher(osv.osv):
journal = journal_pool.browse(cr, uid, journal_id, context=context)
if journal.currency:
return journal.currency.id
- return False
+ return self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
def _get_partner(self, cr, uid, context=None):
if context is None: context = {}
@@ -222,26 +235,26 @@ class account_voucher(osv.osv):
def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, voucher_currency, type, context=None):
context = context or {}
if not line_dr_ids and not line_cr_ids:
- return {'value':{}}
+ return {'value':{'writeoff_amount': 0.0}}
line_osv = self.pool.get("account.voucher.line")
line_dr_ids = resolve_o2m_operations(cr, uid, line_osv, line_dr_ids, ['amount'], context)
line_cr_ids = resolve_o2m_operations(cr, uid, line_osv, line_cr_ids, ['amount'], context)
-
#compute the field is_multi_currency that is used to hide/display options linked to secondary currency on the voucher
is_multi_currency = False
- if voucher_currency:
- # if the voucher currency is not False, it means it is different than the company currency and we need to display the options
- is_multi_currency = True
- else:
- #loop on the voucher lines to see if one of these has a secondary currency. If yes, we need to define the options
- for voucher_line in line_dr_ids+line_cr_ids:
- company_currency = False
- company_currency = voucher_line.get('move_line_id', False) and self.pool.get('account.move.line').browse(cr, uid, voucher_line.get('move_line_id'), context=context).company_id.currency_id.id
- if voucher_line.get('currency_id', company_currency) != company_currency:
- is_multi_currency = True
- break
+ #loop on the voucher lines to see if one of these has a secondary currency. If yes, we need to see the options
+ for voucher_line in line_dr_ids+line_cr_ids:
+ line_id = voucher_line.get('id') and self.pool.get('account.voucher.line').browse(cr, uid, voucher_line['id'], context=context).move_line_id.id or voucher_line.get('move_line_id')
+ if line_id and self.pool.get('account.move.line').browse(cr, uid, line_id, context=context).currency_id:
+ is_multi_currency = True
+ break
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount, type), 'is_multi_currency': is_multi_currency}}
+ def _get_journal_currency(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for voucher in self.browse(cr, uid, ids, context=context):
+ res[voucher.id] = voucher.journal_id.currency and voucher.journal_id.currency.id or voucher.company_id.currency_id.id
+ return res
+
def _get_writeoff_amount(self, cr, uid, ids, name, args, context=None):
if not ids: return {}
currency_obj = self.pool.get('res.currency')
@@ -258,20 +271,48 @@ class account_voucher(osv.osv):
return res
def _paid_amount_in_company_currency(self, cr, uid, ids, name, args, context=None):
- if not ids: return {}
+ if context is None:
+ context = {}
+ res = {}
+ ctx = context.copy()
+ for v in self.browse(cr, uid, ids, context=context):
+ ctx.update({'date': v.date})
+ #make a new call to browse in order to have the right date in the context, to get the right currency rate
+ voucher = self.browse(cr, uid, v.id, context=ctx)
+ ctx.update({
+ 'voucher_special_currency': voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id or False,
+ 'voucher_special_currency_rate': voucher.currency_id.rate * voucher.payment_rate,})
+ res[voucher.id] = self.pool.get('res.currency').compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, voucher.amount, context=ctx)
+ return res
+
+ def _get_currency_help_label(self, cr, uid, currency_id, payment_rate, payment_rate_currency_id, context=None):
+ """
+ This function builds a string to help the users to understand the behavior of the payment rate fields they can specify on the voucher.
+ This string is only used to improve the usability in the voucher form view and has no other effect.
+
+ :param currency_id: the voucher currency
+ :type currency_id: integer
+ :param payment_rate: the value of the payment_rate field of the voucher
+ :type payment_rate: float
+ :param payment_rate_currency_id: the value of the payment_rate_currency_id field of the voucher
+ :type payment_rate_currency_id: integer
+ :return: translated string giving a tip on what's the effect of the current payment rate specified
+ :rtype: str
+ """
+ rml_parser = report_sxw.rml_parse(cr, uid, 'currency_help_label', context=context)
+ currency_pool = self.pool.get('res.currency')
+ currency_str = payment_rate_str = ''
+ if currency_id:
+ currency_str = rml_parser.formatLang(1, currency_obj=currency_pool.browse(cr, uid, currency_id, context=context))
+ if payment_rate_currency_id:
+ payment_rate_str = rml_parser.formatLang(payment_rate, currency_obj=currency_pool.browse(cr, uid, payment_rate_currency_id, context=context))
+ currency_help_label = _('At the operation date, the exchange rate was\n%s = %s') % (currency_str, payment_rate_str)
+ return currency_help_label
+
+ def _fnct_currency_help_label(self, cr, uid, ids, name, args, context=None):
res = {}
- rate = 1.0
for voucher in self.browse(cr, uid, ids, context=context):
- if voucher.currency_id:
- if voucher.company_id.currency_id.id == voucher.payment_rate_currency_id.id:
- rate = 1 / voucher.payment_rate
- else:
- ctx = context.copy()
- ctx.update({'date': voucher.date})
- voucher_rate = self.browse(cr, uid, voucher.id, context=ctx).currency_id.rate
- company_currency_rate = voucher.company_id.currency_id.rate
- rate = voucher_rate * company_currency_rate
- res[voucher.id] = voucher.amount / rate
+ res[voucher.id] = self._get_currency_help_label(cr, uid, voucher.currency_id.id, voucher.payment_rate, voucher.payment_rate_currency_id.id, context=context)
return res
_name = 'account.voucher'
@@ -304,8 +345,7 @@ class account_voucher(osv.osv):
domain=[('type','=','dr')], context={'default_type':'dr'}, readonly=True, states={'draft':[('readonly',False)]}),
'period_id': fields.many2one('account.period', 'Period', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'narration':fields.text('Notes', readonly=True, states={'draft':[('readonly',False)]}),
-# 'currency_id':fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'currency_id': fields.related('journal_id','currency', type='many2one', relation='res.currency', string='Currency', readonly=True),
+ 'currency_id': fields.function(_get_journal_currency, type='many2one', relation='res.currency', string='Currency', readonly=True, required=True),
'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'state':fields.selection(
[('draft','Draft'),
@@ -346,6 +386,7 @@ class account_voucher(osv.osv):
help='The specific rate that will be used, in this voucher, between the selected currency (in \'Payment Rate Currency\' field) and the voucher currency.'),
'paid_amount_in_company_currency': fields.function(_paid_amount_in_company_currency, string='Paid Amount in Company Currency', type='float', readonly=True),
'is_multi_currency': fields.boolean('Multi Currency Voucher', help='Fields with internal purpose only that depicts if the voucher is a multi currency one or not'),
+ 'currency_help_label': fields.function(_fnct_currency_help_label, type='text', string="Helping Sentence", help="This sentence helps you to know how to specify the payment rate by giving you the direct effect it has"),
}
_defaults = {
'active': True,
@@ -422,6 +463,8 @@ class account_voucher(osv.osv):
partner_pool = self.pool.get('res.partner')
position_pool = self.pool.get('account.fiscal.position')
line_pool = self.pool.get('account.voucher.line')
+ if not line_ids:
+ line_ids = []
res = {
'tax_amount': False,
'amount': False,
@@ -516,23 +559,26 @@ class account_voucher(osv.osv):
return default
def onchange_rate(self, cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=None):
- res = {'value': {'paid_amount_in_company_currency': amount}}
- company_currency = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id
- if rate and amount and currency_id:# and currency_id == payment_rate_currency_id:
- voucher_rate = self.pool.get('res.currency').browse(cr, uid, currency_id, context).rate
- if company_currency.id == payment_rate_currency_id:
- company_rate = rate
- else:
- company_rate = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.rate
- res['value']['paid_amount_in_company_currency'] = amount / voucher_rate * company_rate
+ res = {'value': {'paid_amount_in_company_currency': amount, 'currency_help_label': self._get_currency_help_label(cr, uid, currency_id, rate, payment_rate_currency_id, context=context)}}
+ if rate and amount and currency_id:
+ company_currency = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id
+ #context should contain the date, the payment currency and the payment rate specified on the voucher
+ amount_in_company_currency = self.pool.get('res.currency').compute(cr, uid, currency_id, company_currency.id, amount, context=context)
+ res['value']['paid_amount_in_company_currency'] = amount_in_company_currency
return res
def onchange_amount(self, cr, uid, ids, amount, rate, partner_id, journal_id, currency_id, ttype, date, payment_rate_currency_id, company_id, context=None):
if context is None:
context = {}
- res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
ctx = context.copy()
ctx.update({'date': date})
+ #read the voucher rate with the right date in the context
+ currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
+ voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+ ctx.update({
+ 'voucher_special_currency': payment_rate_currency_id,
+ 'voucher_special_currency_rate': rate * voucher_rate})
+ res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=ctx)
vals = self.onchange_rate(cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in vals.keys():
res[key].update(vals[key])
@@ -546,6 +592,7 @@ class account_voucher(osv.osv):
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
company_id = journal.company_id.id
payment_rate = 1.0
+ currency_id = currency_id or journal.company_id.currency_id.id
payment_rate_currency_id = currency_id
ctx = context.copy()
ctx.update({'date': date})
@@ -561,24 +608,62 @@ class account_voucher(osv.osv):
# is not in the voucher currency
payment_rate_currency_id = voucher_line['currency_id']
tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
- voucher_currency_id = currency_id or journal.company_id.currency_id.id
- payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
+ payment_rate = tmp / currency_obj.browse(cr, uid, currency_id, context=ctx).rate
break
+ vals['value'].update({
+ 'payment_rate': payment_rate,
+ 'currency_id': currency_id,
+ 'payment_rate_currency_id': payment_rate_currency_id
+ })
+ #read the voucher rate with the right date in the context
+ voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+ ctx.update({
+ 'voucher_special_currency_rate': payment_rate * voucher_rate,
+ 'voucher_special_currency': payment_rate_currency_id})
res = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in res.keys():
vals[key].update(res[key])
- vals['value'].update({'payment_rate': payment_rate})
- if payment_rate_currency_id:
- vals['value'].update({'payment_rate_currency_id': payment_rate_currency_id})
return vals
+ def basic_onchange_partner(self, cr, uid, ids, partner_id, journal_id, ttype, context=None):
+ partner_pool = self.pool.get('res.partner')
+ journal_pool = self.pool.get('account.journal')
+ res = {'value': {'account_id': False}}
+ if not partner_id or not journal_id:
+ return res
+
+ journal = journal_pool.browse(cr, uid, journal_id, context=context)
+ partner = partner_pool.browse(cr, uid, partner_id, context=context)
+ account_id = False
+ if journal.type in ('sale','sale_refund'):
+ account_id = partner.property_account_receivable.id
+ elif journal.type in ('purchase', 'purchase_refund','expense'):
+ account_id = partner.property_account_payable.id
+ else:
+ account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
+
+ res['value']['account_id'] = account_id
+ return res
+
def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=None):
if not journal_id:
return {}
- res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
- vals = self.recompute_payment_rate(cr, uid, ids, res, currency_id, date, ttype, journal_id, amount, context=context)
+ if context is None:
+ context = {}
+ #TODO: comment me and use me directly in the sales/purchases views
+ res = self.basic_onchange_partner(cr, uid, ids, partner_id, journal_id, ttype, context=context)
+ if ttype in ['sale', 'purchase']:
+ return res
+ ctx = context.copy()
+ # not passing the payment_rate currency and the payment_rate in the context but it's ok because they are reset in recompute_payment_rate
+ ctx.update({'date': date})
+ vals = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=ctx)
+ vals2 = self.recompute_payment_rate(cr, uid, ids, vals, currency_id, date, ttype, journal_id, amount, context=context)
for key in vals.keys():
res[key].update(vals[key])
+ for key in vals2.keys():
+ res[key].update(vals2[key])
+ #TODO: can probably be removed now
#TODO: onchange_partner_id() should not returns [pre_line, line_dr_ids, payment_rate...] for type sale, and not
# [pre_line, line_cr_ids, payment_rate...] for type purchase.
# We should definitively split account.voucher object in two and make distinct on_change functions. In the
@@ -621,8 +706,6 @@ class account_voucher(osv.osv):
if context is None:
context = {}
context_multi_currency = context.copy()
- if date:
- context_multi_currency.update({'date': date})
currency_pool = self.pool.get('res.currency')
move_line_pool = self.pool.get('account.move.line')
@@ -646,18 +729,6 @@ class account_voucher(osv.osv):
journal = journal_pool.browse(cr, uid, journal_id, context=context)
partner = partner_pool.browse(cr, uid, partner_id, context=context)
currency_id = currency_id or journal.company_id.currency_id.id
- account_id = False
- if journal.type in ('sale','sale_refund'):
- account_id = partner.property_account_receivable.id
- elif journal.type in ('purchase', 'purchase_refund','expense'):
- account_id = partner.property_account_payable.id
- else:
- account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
-
- default['value']['account_id'] = account_id
-
- if journal.type not in ('cash', 'bank'):
- return default
total_credit = 0.0
total_debit = 0.0
@@ -715,12 +786,13 @@ class account_voucher(osv.osv):
if _remove_noise_in_o2m():
continue
- if line.currency_id and currency_id==line.currency_id.id:
+ if line.currency_id and currency_id == line.currency_id.id:
amount_original = abs(line.amount_currency)
amount_unreconciled = abs(line.amount_residual_currency)
else:
- amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0)
- amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual))
+ #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
+ amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0, context=context_multi_currency)
+ amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual), context=context_multi_currency)
line_currency_id = line.currency_id and line.currency_id.id or company_currency
rs = {
'name':line.move_id.name,
@@ -766,10 +838,15 @@ class account_voucher(osv.osv):
if context is None:
context = {}
res = {'value': {}}
- #set the default payment rate of the voucher and compute the paid amount in company currency
- if currency_id and currency_id == payment_rate_currency_id:
+ if currency_id:
+ #set the default payment rate of the voucher and compute the paid amount in company currency
ctx = context.copy()
ctx.update({'date': date})
+ #read the voucher rate with the right date in the context
+ voucher_rate = self.pool.get('res.currency').read(cr, uid, currency_id, ['rate'], context=ctx)['rate']
+ ctx.update({
+ 'voucher_special_currency_rate': payment_rate * voucher_rate,
+ 'voucher_special_currency': payment_rate_currency_id})
vals = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in vals.keys():
res[key].update(vals[key])
@@ -789,7 +866,8 @@ class account_voucher(osv.osv):
period_pool = self.pool.get('account.period')
currency_obj = self.pool.get('res.currency')
ctx = context.copy()
- ctx.update({'company_id': company_id})
+ ctx.update({'company_id': company_id, 'account_period_prefer_normal': True})
+ voucher_currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
pids = period_pool.find(cr, uid, date, context=ctx)
if pids:
res['value'].update({'period_id':pids[0]})
@@ -798,9 +876,8 @@ class account_voucher(osv.osv):
payment_rate = 1.0
if payment_rate_currency_id != currency_id:
tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
- voucher_currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
- vals = self.onchange_payment_rate_currency(cr, uid, ids, currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=context)
+ vals = self.onchange_payment_rate_currency(cr, uid, ids, voucher_currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=context)
vals['value'].update({'payment_rate': payment_rate})
for key in vals.keys():
res[key].update(vals[key])
@@ -823,7 +900,15 @@ class account_voucher(osv.osv):
currency_id = False
if journal.currency:
currency_id = journal.currency.id
+ else:
+ currency_id = journal.company_id.currency_id.id
vals['value'].update({'currency_id': currency_id})
+ #in case we want to register the payment directly from an invoice, it's confusing to allow to switch the journal
+ #without seeing that the amount is expressed in the journal currency, and not in the invoice currency. So to avoid
+ #this common mistake, we simply reset the amount to 0 if the currency is not the invoice currency.
+ if context.get('payment_expected_currency') and currency_id != context.get('payment_expected_currency'):
+ vals['value']['amount'] = 0
+ amount = 0
res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context)
for key in res.keys():
vals[key].update(res[key])
@@ -905,8 +990,8 @@ class account_voucher(osv.osv):
current_currency = self._get_current_currency(cr, uid, voucher_id, context)
if current_currency <> company_currency:
context_multi_currency = context.copy()
- voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
- context_multi_currency.update({'date': voucher_brw.date})
+ voucher = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
+ context_multi_currency.update({'date': voucher.date})
return context_multi_currency
return context
@@ -921,33 +1006,33 @@ class account_voucher(osv.osv):
:return: mapping between fieldname and value of account move line to create
:rtype: dict
'''
- voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+ voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
debit = credit = 0.0
# TODO: is there any other alternative then the voucher type ??
# ANSWER: We can have payment and receipt "In Advance".
# TODO: Make this logic available.
# -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
- if voucher_brw.type in ('purchase', 'payment'):
- credit = voucher_brw.paid_amount_in_company_currency
- elif voucher_brw.type in ('sale', 'receipt'):
- debit = voucher_brw.paid_amount_in_company_currency
+ if voucher.type in ('purchase', 'payment'):
+ credit = voucher.paid_amount_in_company_currency
+ elif voucher.type in ('sale', 'receipt'):
+ debit = voucher.paid_amount_in_company_currency
if debit < 0: credit = -debit; debit = 0.0
if credit < 0: debit = -credit; credit = 0.0
sign = debit - credit < 0 and -1 or 1
#set the first line of the voucher
move_line = {
- 'name': voucher_brw.name or '/',
+ 'name': voucher.name or '/',
'debit': debit,
'credit': credit,
- 'account_id': voucher_brw.account_id.id,
+ 'account_id': voucher.account_id.id,
'move_id': move_id,
- 'journal_id': voucher_brw.journal_id.id,
- 'period_id': voucher_brw.period_id.id,
- 'partner_id': voucher_brw.partner_id.id,
+ 'journal_id': voucher.journal_id.id,
+ 'period_id': voucher.period_id.id,
+ 'partner_id': voucher.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
- 'amount_currency': company_currency <> current_currency and sign * voucher_brw.amount or 0.0,
- 'date': voucher_brw.date,
- 'date_maturity': voucher_brw.date_due
+ 'amount_currency': company_currency <> current_currency and sign * voucher.amount or 0.0,
+ 'date': voucher.date,
+ 'date_maturity': voucher.date_due
}
return move_line
@@ -960,31 +1045,31 @@ class account_voucher(osv.osv):
:rtype: dict
'''
seq_obj = self.pool.get('ir.sequence')
- voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
- if voucher_brw.number:
- name = voucher_brw.number
- elif voucher_brw.journal_id.sequence_id:
- if not voucher_brw.journal_id.sequence_id.active:
+ voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+ if voucher.number:
+ name = voucher.number
+ elif voucher.journal_id.sequence_id:
+ if not voucher.journal_id.sequence_id.active:
raise osv.except_osv(_('Configuration Error !'),
_('Please activate the sequence of selected journal !'))
c = dict(context)
- c.update({'fiscalyear_id': voucher_brw.period_id.fiscalyear_id.id})
- name = seq_obj.next_by_id(cr, uid, voucher_brw.journal_id.sequence_id.id, context=c)
+ c.update({'fiscalyear_id': voucher.period_id.fiscalyear_id.id})
+ name = seq_obj.next_by_id(cr, uid, voucher.journal_id.sequence_id.id, context=c)
else:
raise osv.except_osv(_('Error!'),
_('Please define a sequence on the journal.'))
- if not voucher_brw.reference:
+ if not voucher.reference:
ref = name.replace('/','')
else:
- ref = voucher_brw.reference
+ ref = voucher.reference
move = {
'name': name,
- 'journal_id': voucher_brw.journal_id.id,
- 'narration': voucher_brw.narration,
- 'date': voucher_brw.date,
+ 'journal_id': voucher.journal_id.id,
+ 'narration': voucher.narration,
+ 'date': voucher.date,
'ref': ref,
- 'period_id': voucher_brw.period_id.id,
+ 'period_id': voucher.period_id.id,
}
return move
@@ -1011,7 +1096,10 @@ class account_voucher(osv.osv):
raise osv.except_osv(_('Insufficient Configuration!'),_("You should configure the 'Gain Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
# Even if the amount_currency is never filled, we need to pass the foreign currency because otherwise
# the receivable/payable account may have a secondary currency, which render this field mandatory
- account_currency_id = company_currency <> current_currency and current_currency or False
+ if line.account_id.currency_id:
+ account_currency_id = line.account_id.currency_id.id
+ else:
+ account_currency_id = company_currency <> current_currency and current_currency or False
move_line = {
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
@@ -1054,16 +1142,11 @@ class account_voucher(osv.osv):
:return: the amount in the currency of the voucher's company
:rtype: float
'''
+ if context is None:
+ context = {}
currency_obj = self.pool.get('res.currency')
voucher = self.browse(cr, uid, voucher_id, context=context)
- res = amount
- if voucher.payment_rate_currency_id.id == voucher.company_id.currency_id.id:
- # the rate specified on the voucher is for the company currency
- res = currency_obj.round(cr, uid, voucher.company_id.currency_id, (amount * voucher.payment_rate))
- else:
- # the rate specified on the voucher is not relevant, we use all the rates in the system
- res = currency_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=context)
- return res
+ return currency_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=context)
def voucher_move_line_create(self, cr, uid, voucher_id, line_total, move_id, company_currency, current_currency, context=None):
'''
@@ -1087,39 +1170,45 @@ class account_voucher(osv.osv):
tot_line = line_total
rec_lst_ids = []
- voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
+ date = self.read(cr, uid, voucher_id, ['date'], context=context)['date']
ctx = context.copy()
- ctx.update({'date': voucher_brw.date})
+ ctx.update({'date': date})
+ voucher = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context=ctx)
+ voucher_currency = voucher.journal_id.currency or voucher.company_id.currency_id
+ ctx.update({
+ 'voucher_special_currency_rate': voucher_currency.rate * voucher.payment_rate ,
+ 'voucher_special_currency': voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id or False,})
prec = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
- for line in voucher_brw.line_ids:
+ for line in voucher.line_ids:
#create one move line per voucher line where amount is not 0.0
# AND (second part of the clause) only if the original move line was not having debit = credit = 0 (which is a legal value)
if not line.amount and not (line.move_line_id and not float_compare(line.move_line_id.debit, line.move_line_id.credit, precision_rounding=prec) and not float_compare(line.move_line_id.debit, 0.0, precision_rounding=prec)):
continue
# convert the amount set on the voucher line into the currency of the voucher's company
- amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher_brw.id, context=ctx)
+ # this calls res_curreny.compute() with the right context, so that it will take either the rate on the voucher if it is relevant or will use the default behaviour
+ amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher.id, context=ctx)
# if the amount encoded in voucher is equal to the amount unreconciled, we need to compute the
# currency rate difference
if line.amount == line.amount_unreconciled:
if not line.move_line_id:
raise osv.except_osv(_('Wrong voucher line'),_("The invoice you are willing to pay is not valid anymore."))
- sign = voucher_brw.type in ('payment', 'purchase') and -1 or 1
+ sign = voucher.type in ('payment', 'purchase') and -1 or 1
currency_rate_difference = sign * (line.move_line_id.amount_residual - amount)
else:
currency_rate_difference = 0.0
move_line = {
- 'journal_id': voucher_brw.journal_id.id,
- 'period_id': voucher_brw.period_id.id,
+ 'journal_id': voucher.journal_id.id,
+ 'period_id': voucher.period_id.id,
'name': line.name or '/',
'account_id': line.account_id.id,
'move_id': move_id,
- 'partner_id': voucher_brw.partner_id.id,
+ 'partner_id': voucher.partner_id.id,
'currency_id': line.move_line_id and (company_currency <> line.move_line_id.currency_id.id and line.move_line_id.currency_id.id) or False,
'analytic_account_id': line.account_analytic_id and line.account_analytic_id.id or False,
'quantity': 1,
'credit': 0.0,
'debit': 0.0,
- 'date': voucher_brw.date
+ 'date': voucher.date
}
if amount < 0:
amount = -amount
@@ -1135,9 +1224,9 @@ class account_voucher(osv.osv):
tot_line -= amount
move_line['credit'] = amount
- if voucher_brw.tax_id and voucher_brw.type in ('sale', 'purchase'):
+ if voucher.tax_id and voucher.type in ('sale', 'purchase'):
move_line.update({
- 'account_tax_id': voucher_brw.tax_id.id,
+ 'account_tax_id': voucher.tax_id.id,
})
if move_line.get('account_tax_id', False):
@@ -1149,7 +1238,6 @@ class account_voucher(osv.osv):
foreign_currency_diff = 0.0
amount_currency = False
if line.move_line_id:
- voucher_currency = voucher_brw.currency_id and voucher_brw.currency_id.id or voucher_brw.journal_id.company_id.currency_id.id
# We want to set it on the account move line as soon as the original line had a foreign currency
if line.move_line_id.currency_id and line.move_line_id.currency_id.id != company_currency:
# we compute the amount in that foreign currency.
@@ -1157,22 +1245,19 @@ class account_voucher(osv.osv):
# if the voucher and the voucher line share the same currency, there is no computation to do
sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
amount_currency = sign * (line.amount)
- elif line.move_line_id.currency_id.id == voucher_brw.payment_rate_currency_id.id:
- # if the rate is specified on the voucher, we must use it
- voucher_rate = currency_obj.browse(cr, uid, voucher_currency, context=ctx).rate
- amount_currency = (move_line['debit'] - move_line['credit']) * voucher_brw.payment_rate * voucher_rate
else:
- # otherwise we use the rates of the system (giving the voucher date in the context)
+ # if the rate is specified on the voucher, it will be used thanks to the special keys in the context
+ # otherwise we use the rates of the system
amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
- if line.amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:
- sign = voucher_brw.type in ('payment', 'purchase') and -1 or 1
+ if line.amount == line.amount_unreconciled:
+ sign = voucher.type in ('payment', 'purchase') and -1 or 1
foreign_currency_diff = sign * line.move_line_id.amount_residual_currency + amount_currency
move_line['amount_currency'] = amount_currency
voucher_line = move_line_obj.create(cr, uid, move_line)
rec_ids = [voucher_line, line.move_line_id.id]
- if not currency_obj.is_zero(cr, uid, voucher_brw.company_id.currency_id, currency_rate_difference):
+ if not currency_obj.is_zero(cr, uid, voucher.company_id.currency_id, currency_rate_difference):
# Change difference entry in company currency
exch_lines = self._get_exchange_lines(cr, uid, line, move_id, currency_rate_difference, company_currency, current_currency, context=context)
new_id = move_line_obj.create(cr, uid, exch_lines[0],context)
@@ -1219,32 +1304,32 @@ class account_voucher(osv.osv):
currency_obj = self.pool.get('res.currency')
move_line = {}
- voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
- current_currency_obj = voucher_brw.currency_id or voucher_brw.journal_id.company_id.currency_id
+ voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
+ current_currency_obj = voucher.currency_id or voucher.journal_id.company_id.currency_id
if not currency_obj.is_zero(cr, uid, current_currency_obj, line_total):
diff = line_total
account_id = False
write_off_name = ''
- if voucher_brw.payment_option == 'with_writeoff':
- account_id = voucher_brw.writeoff_acc_id.id
- write_off_name = voucher_brw.comment
- elif voucher_brw.type in ('sale', 'receipt'):
- account_id = voucher_brw.partner_id.property_account_receivable.id
+ if voucher.payment_option == 'with_writeoff':
+ account_id = voucher.writeoff_acc_id.id
+ write_off_name = voucher.comment
+ elif voucher.type in ('sale', 'receipt'):
+ account_id = voucher.partner_id.property_account_receivable.id
else:
- account_id = voucher_brw.partner_id.property_account_payable.id
- sign = voucher_brw.type == 'payment' and -1 or 1
+ account_id = voucher.partner_id.property_account_payable.id
+ sign = voucher.type == 'payment' and -1 or 1
move_line = {
'name': write_off_name or name,
'account_id': account_id,
'move_id': move_id,
- 'partner_id': voucher_brw.partner_id.id,
- 'date': voucher_brw.date,
+ 'partner_id': voucher.partner_id.id,
+ 'date': voucher.date,
'credit': diff > 0 and diff or 0.0,
'debit': diff < 0 and -diff or 0.0,
- 'amount_currency': company_currency <> current_currency and (sign * -1 * voucher_brw.writeoff_amount) or False,
+ 'amount_currency': company_currency <> current_currency and (sign * -1 * voucher.writeoff_amount) or False,
'currency_id': company_currency <> current_currency and current_currency or False,
- 'analytic_account_id': voucher_brw.analytic_id and voucher_brw.analytic_id.id or False,
+ 'analytic_account_id': voucher.analytic_id and voucher.analytic_id.id or False,
}
return move_line
@@ -1345,13 +1430,17 @@ class account_voucher_line(osv.osv):
_order = "move_line_id"
# If the payment is in the same currency than the invoice, we keep the same amount
- # Otherwise, we compute from company currency to payment currency
+ # Otherwise, we compute from invoice currency to payment currency
def _compute_balance(self, cr, uid, ids, name, args, context=None):
currency_pool = self.pool.get('res.currency')
rs_data = {}
for line in self.browse(cr, uid, ids, context=context):
ctx = context.copy()
ctx.update({'date': line.voucher_id.date})
+ voucher_rate = self.pool.get('res.currency').read(cr, uid, line.voucher_id.currency_id.id, ['rate'], context=ctx)['rate']
+ ctx.update({
+ 'voucher_special_currency': line.voucher_id.payment_rate_currency_id and line.voucher_id.payment_rate_currency_id.id or False,
+ 'voucher_special_currency_rate': line.voucher_id.payment_rate * voucher_rate})
res = {}
company_currency = line.voucher_id.journal_id.company_id.currency_id.id
voucher_currency = line.voucher_id.currency_id and line.voucher_id.currency_id.id or company_currency
@@ -1361,13 +1450,11 @@ class account_voucher_line(osv.osv):
res['amount_original'] = 0.0
res['amount_unreconciled'] = 0.0
elif move_line.currency_id and voucher_currency==move_line.currency_id.id:
- res['amount_original'] = currency_pool.compute(cr, uid, move_line.currency_id.id, voucher_currency, abs(move_line.amount_currency), context=ctx)
- res['amount_unreconciled'] = currency_pool.compute(cr, uid, move_line.currency_id and move_line.currency_id.id or company_currency, voucher_currency, abs(move_line.amount_residual_currency), context=ctx)
- elif move_line and move_line.credit > 0:
- res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit, context=ctx)
- res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, abs(move_line.amount_residual), context=ctx)
+ res['amount_original'] = abs(move_line.amount_currency)
+ res['amount_unreconciled'] = abs(move_line.amount_residual_currency)
else:
- res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.debit, context=ctx)
+ #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
+ res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit or move_line.debit or 0.0, context=ctx)
res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, abs(move_line.amount_residual), context=ctx)
rs_data[line.id] = res
@@ -1535,7 +1622,7 @@ class account_bank_statement(osv.osv):
for bk_st in self.browse(cr, uid, ids, context=context):
if vals.get('journal_id') and bk_st.line_ids:
if any([x.voucher_id and True or False for x in bk_st.line_ids]):
- raise osv.except_osv(_('Unable to change journal !'), _('You can not change the journal as you already reconciled some statement lines!'))
+ raise osv.except_osv(_('Unable to Change Journal!'), _('You can not change the journal as you already reconciled some statement lines!'))
return super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
diff --git a/addons/account_voucher/i18n/nl_BE.po b/addons/account_voucher/i18n/nl_BE.po
index 0cdc8cd8399..04366df488e 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-07-10 09:54+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-07-11 05:17+0000\n"
+"X-Generator: Launchpad (build 16696)\n"
"Language: nl\n"
#. module: account_voucher
@@ -28,7 +28,7 @@ msgid "account.config.settings"
msgstr "account.config.settings"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:369
+#: code:addons/account_voucher/account_voucher.py:417
#, python-format
msgid "Write-Off"
msgstr "Afschrijving"
@@ -132,12 +132,14 @@ msgid "Voucher Statistics"
msgstr "Boekingsstatistieken"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1547
+#: code:addons/account_voucher/account_voucher.py:1641
#, python-format
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
@@ -231,8 +233,8 @@ msgid "Journal Item"
msgstr "Boekingslijn"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:508
-#: code:addons/account_voucher/account_voucher.py:981
+#: code:addons/account_voucher/account_voucher.py:558
+#: code:addons/account_voucher/account_voucher.py:1073
#, python-format
msgid "Error!"
msgstr "Fout"
@@ -259,7 +261,7 @@ msgid "Cancelled"
msgstr "Geannuleerd"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1153
+#: code:addons/account_voucher/account_voucher.py:1249
#, python-format
msgid ""
"You have to configure account base code and account tax code on the '%s' tax!"
@@ -311,7 +313,7 @@ msgid "Tax"
msgstr "Btw"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:879
+#: code:addons/account_voucher/account_voucher.py:971
#, python-format
msgid "Invalid Action!"
msgstr "Ongeldige actie"
@@ -364,10 +366,10 @@ msgid "Import Invoices"
msgstr "Facturen importeren"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1112
+#: code:addons/account_voucher/account_voucher.py:1208
#, python-format
msgid "Wrong voucher line"
-msgstr ""
+msgstr "Verkeerde betalingsregel"
#. module: account_voucher
#: selection:account.voucher,pay_now:0
@@ -383,7 +385,7 @@ msgid "Receipt"
msgstr "Reçu"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1018
+#: code:addons/account_voucher/account_voucher.py:1110
#, python-format
msgid ""
"You should configure the 'Gain Exchange Rate Account' in the accounting "
@@ -407,7 +409,7 @@ msgstr "Periode"
#. module: account_voucher
#: view:account.voucher:0
-#: code:addons/account_voucher/account_voucher.py:211
+#: code:addons/account_voucher/account_voucher.py:231
#, python-format
msgid "Supplier"
msgstr "Leverancier"
@@ -428,10 +430,10 @@ msgid "Debit"
msgstr "Debet"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1547
+#: code:addons/account_voucher/account_voucher.py:1641
#, python-format
msgid "Unable to change journal !"
-msgstr ""
+msgstr "Het dagboek kan niet worden gewijzigd"
#. module: account_voucher
#: view:sale.receipt.report:0
@@ -467,6 +469,12 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik hier als u een nieuwe leveranciersbetaling wilt maken.\n"
+"
\n"
+" Met OpenERP kunt u betalingen aan leveranciers opvolgen.\n"
+"
\n"
+" "
#. module: account_voucher
#: view:account.voucher:0
@@ -534,7 +542,7 @@ msgid "Pay Invoice"
msgstr "Factuur betalen"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1153
+#: code:addons/account_voucher/account_voucher.py:1249
#, python-format
msgid "No Account Base Code and Account Tax Code!"
msgstr "Geen rekening voor basisvak en btw-vak"
@@ -588,15 +596,15 @@ msgid "To Review"
msgstr "Te controleren"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1025
-#: code:addons/account_voucher/account_voucher.py:1039
-#: code:addons/account_voucher/account_voucher.py:1194
+#: code:addons/account_voucher/account_voucher.py:1120
+#: code:addons/account_voucher/account_voucher.py:1134
+#: code:addons/account_voucher/account_voucher.py:1286
#, python-format
msgid "change"
msgstr "wijzigen"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1014
+#: code:addons/account_voucher/account_voucher.py:1106
#, python-format
msgid ""
"You should configure the 'Loss Exchange Rate Account' in the accounting "
@@ -654,6 +662,7 @@ msgstr "Maand"
#. module: account_voucher
#: field:account.voucher,currency_id:0
#: field:account.voucher.line,currency_id:0
+#: model:ir.model,name:account_voucher.model_res_currency
#: field:sale.receipt.report,currency_id:0
msgid "Currency"
msgstr "Munt"
@@ -697,7 +706,7 @@ msgid "Reconcile Payment Balance"
msgstr "Betalingssaldo afpunten"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:975
+#: code:addons/account_voucher/account_voucher.py:1067
#, python-format
msgid "Configuration Error !"
msgstr "Configuratiefout"
@@ -745,7 +754,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
@@ -762,7 +771,7 @@ msgid "October"
msgstr "Oktober"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:976
+#: code:addons/account_voucher/account_voucher.py:1068
#, python-format
msgid "Please activate the sequence of selected journal !"
msgstr "Gelieve de nummering van het gekozen journaal te activeren."
@@ -786,7 +795,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 +843,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
@@ -842,10 +851,10 @@ msgid "Previous Payments ?"
msgstr "Vorige betalingen?"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1112
+#: code:addons/account_voucher/account_voucher.py:1208
#, 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
@@ -874,7 +883,7 @@ msgid "Active"
msgstr "Actief"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:982
+#: code:addons/account_voucher/account_voucher.py:1074
#, python-format
msgid "Please define a sequence on the journal."
msgstr "Gelieve een reeks in te stellen voor het journaal."
@@ -884,7 +893,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 +947,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
@@ -1002,7 +1011,7 @@ msgid "Journal Items"
msgstr "Boekingslijnen"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:508
+#: code:addons/account_voucher/account_voucher.py:558
#, python-format
msgid "Please define default credit/debit accounts on the journal \"%s\"."
msgstr "Stel een standaard debet-/creditrekening in voor journaal \"%s\"."
@@ -1219,7 +1228,7 @@ msgstr ""
"Het bedrag van het reçu moet gelijk zijn aan het bedrag op de uittreksellijn."
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:879
+#: code:addons/account_voucher/account_voucher.py:971
#, python-format
msgid "Cannot delete voucher(s) which are already opened or paid."
msgstr "Een openstaand of betaald reçu kan niet meer worden verwijderd."
@@ -1279,11 +1288,11 @@ 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
-#: code:addons/account_voucher/account_voucher.py:1018
+#: code:addons/account_voucher/account_voucher.py:1106
+#: code:addons/account_voucher/account_voucher.py:1110
#, python-format
msgid "Insufficient Configuration!"
msgstr "Niet volledig geconfigureerd"
diff --git a/addons/account_voucher/i18n/ru.po b/addons/account_voucher/i18n/ru.po
index 63cad344ed0..16e03d424ef 100644
--- a/addons/account_voucher/i18n/ru.po
+++ b/addons/account_voucher/i18n/ru.po
@@ -7,27 +7,27 @@ 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-05-10 17:46+0000\n"
+"PO-Revision-Date: 2013-06-13 11:30+0000\n"
"Last-Translator: Chertykov Denis \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:33+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-14 05:38+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
#. module: account_voucher
#: field:account.bank.statement.line,voucher_id:0
msgid "Reconciliation"
-msgstr ""
+msgstr "Сверка"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_config_settings
msgid "account.config.settings"
-msgstr ""
+msgstr "account.config.settings"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:369
+#: code:addons/account_voucher/account_voucher.py:417
#, python-format
msgid "Write-Off"
msgstr "Списание"
@@ -45,7 +45,7 @@ msgstr "Общая сумма"
#. module: account_voucher
#: view:account.voucher:0
msgid "Open Customer Journal Entries"
-msgstr ""
+msgstr "Открыть записи журнала по заказчику"
#. module: account_voucher
#: view:account.voucher:0
@@ -63,7 +63,7 @@ msgstr ""
#. module: account_voucher
#: view:account.voucher:0
msgid "(Update)"
-msgstr ""
+msgstr "(Обновить)"
#. module: account_voucher
#: view:account.voucher:0
@@ -90,7 +90,7 @@ msgstr "Март"
#. module: account_voucher
#: field:account.voucher,message_unread:0
msgid "Unread Messages"
-msgstr ""
+msgstr "Непрочитанные"
#. module: account_voucher
#: view:account.voucher:0
@@ -115,13 +115,13 @@ msgstr "Номер транзакции."
#. module: account_voucher
#: view:sale.receipt.report:0
msgid "Group by year of Invoice Date"
-msgstr ""
+msgstr "Группировать по году в дате счета"
#. module: account_voucher
#: view:sale.receipt.report:0
#: field:sale.receipt.report,user_id:0
msgid "Salesperson"
-msgstr ""
+msgstr "Продавец"
#. module: account_voucher
#: view:account.voucher:0
@@ -129,12 +129,14 @@ msgid "Voucher Statistics"
msgstr ""
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1547
+#: code:addons/account_voucher/account_voucher.py:1641
#, python-format
msgid ""
"You can not change the journal as you already reconciled some statement "
"lines!"
msgstr ""
+"Вы не можете изменить журнал, так как вы уже сверили некоторые позиции "
+"документа!"
#. module: account_voucher
#: view:account.voucher:0
@@ -145,7 +147,7 @@ msgstr "Утвердить"
#: 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 "Оплаты поставщикам"
#. module: account_voucher
#: model:ir.actions.act_window,help:account_voucher.action_purchase_receipt
@@ -167,7 +169,7 @@ msgstr "Искать ваучеры"
#. module: account_voucher
#: field:account.voucher,writeoff_acc_id:0
msgid "Counterpart Account"
-msgstr ""
+msgstr "Корреспондирующий счет"
#. module: account_voucher
#: field:account.voucher,account_id:0
@@ -189,7 +191,7 @@ msgstr "OK"
#. module: account_voucher
#: field:account.voucher.line,reconcile:0
msgid "Full Reconcile"
-msgstr ""
+msgstr "Полная сверка"
#. module: account_voucher
#: field:account.voucher,date_due:0
@@ -207,7 +209,7 @@ msgstr "Примечания"
#. module: account_voucher
#: field:account.voucher,message_ids:0
msgid "Messages"
-msgstr ""
+msgstr "Сообщения"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_purchase_receipt
@@ -221,11 +223,11 @@ msgid "Journal Item"
msgstr "Элемент журнала"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:508
-#: code:addons/account_voucher/account_voucher.py:981
+#: code:addons/account_voucher/account_voucher.py:558
+#: code:addons/account_voucher/account_voucher.py:1073
#, python-format
msgid "Error!"
-msgstr ""
+msgstr "Ошибка!"
#. module: account_voucher
#: field:account.voucher.line,amount:0
@@ -235,7 +237,7 @@ msgstr "Суммма"
#. module: account_voucher
#: view:account.voucher:0
msgid "Payment Options"
-msgstr ""
+msgstr "Варианты оплаты"
#. module: account_voucher
#: view:account.voucher:0
@@ -249,11 +251,13 @@ msgid "Cancelled"
msgstr "Отменено"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1153
+#: code:addons/account_voucher/account_voucher.py:1249
#, python-format
msgid ""
"You have to configure account base code and account tax code on the '%s' tax!"
msgstr ""
+"Вы должны настроить код базового счета и код налогового счета для налога "
+"'%s'!"
#. module: account_voucher
#: model:ir.actions.act_window,help:account_voucher.action_sale_receipt
@@ -271,7 +275,7 @@ msgstr ""
#. module: account_voucher
#: help:account.voucher,message_unread:0
msgid "If checked new messages require your attention."
-msgstr ""
+msgstr "Если отмечено, новые сообщения требуют вашего внимания."
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_bank_statement_line
@@ -291,15 +295,15 @@ msgid "Tax"
msgstr "Налог"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:879
+#: code:addons/account_voucher/account_voucher.py:971
#, python-format
msgid "Invalid Action!"
-msgstr ""
+msgstr "Неверное действие!"
#. module: account_voucher
#: field:account.voucher,comment:0
msgid "Counterpart Comment"
-msgstr ""
+msgstr "Корреспондирующий коментарий"
#. module: account_voucher
#: field:account.voucher.line,account_analytic_id:0
@@ -312,6 +316,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 ""
+"Содержит сводку по Чаттеру (количество сообщений,...). Эта сводка в формате "
+"html для возможности использования в канбан виде"
#. module: account_voucher
#: view:account.voucher:0
@@ -326,7 +332,7 @@ msgstr "Информация о платеже"
#. module: account_voucher
#: view:account.voucher:0
msgid "(update)"
-msgstr ""
+msgstr "(обновить)"
#. module: account_voucher
#: view:account.voucher:0
@@ -342,7 +348,7 @@ msgid "Import Invoices"
msgstr "Импорт счетов"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1112
+#: code:addons/account_voucher/account_voucher.py:1208
#, python-format
msgid "Wrong voucher line"
msgstr ""
@@ -361,7 +367,7 @@ msgid "Receipt"
msgstr "Приход"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1018
+#: code:addons/account_voucher/account_voucher.py:1110
#, python-format
msgid ""
"You should configure the 'Gain Exchange Rate Account' in the accounting "
@@ -382,7 +388,7 @@ msgstr "Период"
#. module: account_voucher
#: view:account.voucher:0
-#: code:addons/account_voucher/account_voucher.py:211
+#: code:addons/account_voucher/account_voucher.py:231
#, python-format
msgid "Supplier"
msgstr "Поставщик"
@@ -395,7 +401,7 @@ msgstr "Ваучер поставщика"
#. module: account_voucher
#: field:account.voucher,message_follower_ids:0
msgid "Followers"
-msgstr ""
+msgstr "Подписчики"
#. module: account_voucher
#: selection:account.voucher.line,type:0
@@ -403,10 +409,10 @@ msgid "Debit"
msgstr "Дебет"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1547
+#: code:addons/account_voucher/account_voucher.py:1641
#, python-format
msgid "Unable to change journal !"
-msgstr ""
+msgstr "Невозможно изменить журнал!"
#. module: account_voucher
#: view:sale.receipt.report:0
@@ -446,7 +452,7 @@ msgstr ""
#. module: account_voucher
#: view:account.voucher:0
msgid "Open Supplier Journal Entries"
-msgstr ""
+msgstr "Открыть журнал проводок по поставщику"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_review_voucher_list
@@ -461,7 +467,7 @@ msgstr "Памятка"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure to unreconcile and cancel this record ?"
-msgstr ""
+msgstr "Вы уверены, что надо отменить сверку и саму запись ?"
#. module: account_voucher
#: field:account.voucher,is_multi_currency:0
@@ -494,13 +500,13 @@ msgstr ""
#. module: account_voucher
#: field:account.voucher,writeoff_amount:0
msgid "Difference Amount"
-msgstr ""
+msgstr "Сумма разницы"
#. module: account_voucher
#: view:sale.receipt.report:0
#: field:sale.receipt.report,due_delay:0
msgid "Avg. Due Delay"
-msgstr ""
+msgstr "Средн. задержка"
#. module: account_voucher
#: code:addons/account_voucher/invoice.py:34
@@ -509,7 +515,7 @@ msgid "Pay Invoice"
msgstr "Оплата счета"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1153
+#: code:addons/account_voucher/account_voucher.py:1249
#, python-format
msgid "No Account Base Code and Account Tax Code!"
msgstr ""
@@ -554,7 +560,7 @@ msgstr "Оплаченная сумма"
#. module: account_voucher
#: field:account.voucher,payment_option:0
msgid "Payment Difference"
-msgstr ""
+msgstr "Оплата разницы"
#. module: account_voucher
#: view:account.voucher:0
@@ -563,15 +569,15 @@ msgid "To Review"
msgstr "Для проверки"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1025
-#: code:addons/account_voucher/account_voucher.py:1039
-#: code:addons/account_voucher/account_voucher.py:1194
+#: code:addons/account_voucher/account_voucher.py:1120
+#: code:addons/account_voucher/account_voucher.py:1134
+#: code:addons/account_voucher/account_voucher.py:1286
#, python-format
msgid "change"
-msgstr ""
+msgstr "изменить"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1014
+#: code:addons/account_voucher/account_voucher.py:1106
#, python-format
msgid ""
"You should configure the 'Loss Exchange Rate Account' in the accounting "
@@ -599,7 +605,7 @@ msgstr ""
#. module: account_voucher
#: view:account.invoice:0
msgid "Register Payment"
-msgstr ""
+msgstr "Регистрация оплаты"
#. module: account_voucher
#: field:account.statement.from.invoice.lines,line_ids:0
@@ -614,7 +620,7 @@ msgstr "декабрём"
#. module: account_voucher
#: view:sale.receipt.report:0
msgid "Group by month of Invoice Date"
-msgstr ""
+msgstr "Группировать по месяцу даты счета"
#. module: account_voucher
#: view:sale.receipt.report:0
@@ -625,6 +631,7 @@ msgstr "Месяц"
#. module: account_voucher
#: field:account.voucher,currency_id:0
#: field:account.voucher.line,currency_id:0
+#: model:ir.model,name:account_voucher.model_res_currency
#: field:sale.receipt.report,currency_id:0
msgid "Currency"
msgstr "Валюта"
@@ -647,7 +654,7 @@ msgstr ""
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure to unreconcile this record?"
-msgstr ""
+msgstr "Вы уверены в отмене сверки"
#. module: account_voucher
#: field:account.voucher,company_id:0
@@ -665,13 +672,13 @@ msgstr ""
#. module: account_voucher
#: selection:account.voucher,payment_option:0
msgid "Reconcile Payment Balance"
-msgstr ""
+msgstr "Сверка платежного баланса"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:975
+#: code:addons/account_voucher/account_voucher.py:1067
#, python-format
msgid "Configuration Error !"
-msgstr ""
+msgstr "Ошибка конфигурации !"
#. module: account_voucher
#: view:account.voucher:0
@@ -695,18 +702,18 @@ msgstr ""
#: field:account.voucher,state:0
#: view:sale.receipt.report:0
msgid "Status"
-msgstr ""
+msgstr "Статус"
#. module: account_voucher
#: view:account.voucher:0
msgid "Allocation"
-msgstr ""
+msgstr "Распределение"
#. module: account_voucher
#: view:account.statement.from.invoice.lines:0
#: view:account.voucher:0
msgid "or"
-msgstr ""
+msgstr "или"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@@ -716,7 +723,7 @@ msgstr "Август"
#. module: account_voucher
#: view:account.voucher:0
msgid "Validate Payment"
-msgstr ""
+msgstr "Утвердить оплату"
#. module: account_voucher
#: help:account.voucher,audit:0
@@ -724,6 +731,8 @@ msgid ""
"Check this box if you are unsure of that journal entry and if you want to "
"note it as 'to be reviewed' by an accounting expert."
msgstr ""
+"Отметьте, если вы не уверены в этой проводке журнала и хотите отметить её "
+"\"для проверки\" опытному бухгалтеру."
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@@ -731,10 +740,10 @@ msgid "October"
msgstr "Октябрь"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:976
+#: code:addons/account_voucher/account_voucher.py:1068
#, python-format
msgid "Please activate the sequence of selected journal !"
-msgstr ""
+msgstr "Пожалуйста, включите нумерацию выбранного журнала!"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@@ -749,7 +758,7 @@ msgstr ""
#. module: account_voucher
#: field:account.voucher,paid:0
msgid "Paid"
-msgstr ""
+msgstr "Оплачено"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt
@@ -760,7 +769,7 @@ msgstr ""
#. module: account_voucher
#: field:account.voucher,message_is_follower:0
msgid "Is a Follower"
-msgstr ""
+msgstr "Подписан"
#. module: account_voucher
#: field:account.voucher,analytic_id:0
@@ -787,7 +796,7 @@ msgstr "Расширенные фильтры..."
#. module: account_voucher
#: field:account.voucher,paid_amount_in_company_currency:0
msgid "Paid Amount in Company Currency"
-msgstr ""
+msgstr "Оплаченная сумма в валюте компании"
#. module: account_voucher
#: field:account.bank.statement.line,amount_reconciled:0
@@ -811,10 +820,10 @@ msgid "Previous Payments ?"
msgstr "Предыдущие платежи ?"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1112
+#: code:addons/account_voucher/account_voucher.py:1208
#, python-format
msgid "The invoice you are willing to pay is not valid anymore."
-msgstr ""
+msgstr "Счет, который вы готовы платить, уже не актуален ."
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@@ -830,30 +839,30 @@ msgstr "Журнал ваучеров"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_res_company
msgid "Companies"
-msgstr ""
+msgstr "Компании"
#. module: account_voucher
#: field:account.voucher,message_summary:0
msgid "Summary"
-msgstr ""
+msgstr "Итог"
#. module: account_voucher
#: field:account.voucher,active:0
msgid "Active"
-msgstr ""
+msgstr "Активно"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:982
+#: code:addons/account_voucher/account_voucher.py:1074
#, python-format
msgid "Please define a sequence on the journal."
-msgstr ""
+msgstr "Пожалуйста, определите нумерацию журнала."
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.act_pay_voucher
#: 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 "Платежи заказчиков"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt_report_all
@@ -865,7 +874,7 @@ msgstr ""
#. module: account_voucher
#: view:sale.receipt.report:0
msgid "Group by Invoice Date"
-msgstr ""
+msgstr "Группировать по дате счета"
#. module: account_voucher
#: view:account.voucher:0
@@ -971,7 +980,7 @@ msgid "Journal Items"
msgstr "Элементы журнала"
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:508
+#: code:addons/account_voucher/account_voucher.py:558
#, python-format
msgid "Please define default credit/debit accounts on the journal \"%s\"."
msgstr ""
@@ -1180,7 +1189,7 @@ msgid ""
msgstr ""
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:879
+#: code:addons/account_voucher/account_voucher.py:971
#, python-format
msgid "Cannot delete voucher(s) which are already opened or paid."
msgstr ""
@@ -1243,8 +1252,8 @@ msgid "Status changed"
msgstr ""
#. module: account_voucher
-#: code:addons/account_voucher/account_voucher.py:1014
-#: code:addons/account_voucher/account_voucher.py:1018
+#: code:addons/account_voucher/account_voucher.py:1106
+#: code:addons/account_voucher/account_voucher.py:1110
#, python-format
msgid "Insufficient Configuration!"
msgstr ""
diff --git a/addons/account_voucher/invoice.py b/addons/account_voucher/invoice.py
index 03a3e5fab67..c11f9d532e9 100644
--- a/addons/account_voucher/invoice.py
+++ b/addons/account_voucher/invoice.py
@@ -41,6 +41,7 @@ class invoice(osv.osv):
'target': 'new',
'domain': '[]',
'context': {
+ 'payment_expected_currency': inv.currency_id.id,
'default_partner_id': self.pool.get('res.partner')._find_accounting_partner(inv.partner_id).id,
'default_amount': inv.type in ('out_refund', 'in_refund') and -inv.residual or inv.residual,
'default_reference': inv.name,
diff --git a/addons/account_voucher/security/account_voucher_security.xml b/addons/account_voucher/security/account_voucher_security.xml
index 04540fd8aa0..daa5934b256 100644
--- a/addons/account_voucher/security/account_voucher_security.xml
+++ b/addons/account_voucher/security/account_voucher_security.xml
@@ -3,13 +3,13 @@
Voucher multi-company
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]Voucher Line multi-company
-
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
diff --git a/addons/account_voucher/static/description/account_illu_01.png b/addons/account_voucher/static/description/account_illu_01.png
new file mode 100644
index 00000000000..2e0dbf4aac2
Binary files /dev/null and b/addons/account_voucher/static/description/account_illu_01.png differ
diff --git a/addons/account_voucher/static/description/account_sc_00.png b/addons/account_voucher/static/description/account_sc_00.png
new file mode 100644
index 00000000000..63332b46575
Binary files /dev/null and b/addons/account_voucher/static/description/account_sc_00.png differ
diff --git a/addons/account_voucher/static/description/account_sc_02.png b/addons/account_voucher/static/description/account_sc_02.png
new file mode 100644
index 00000000000..709e444ba0d
Binary files /dev/null and b/addons/account_voucher/static/description/account_sc_02.png differ
diff --git a/addons/account_voucher/static/description/account_sc_03.png b/addons/account_voucher/static/description/account_sc_03.png
new file mode 100644
index 00000000000..a3e3afc34c0
Binary files /dev/null and b/addons/account_voucher/static/description/account_sc_03.png differ
diff --git a/addons/account_voucher/static/description/account_sc_04.png b/addons/account_voucher/static/description/account_sc_04.png
new file mode 100644
index 00000000000..458c8280c26
Binary files /dev/null and b/addons/account_voucher/static/description/account_sc_04.png differ
diff --git a/addons/account_voucher/static/description/account_sc_06.png b/addons/account_voucher/static/description/account_sc_06.png
new file mode 100644
index 00000000000..9605506c6a5
Binary files /dev/null and b/addons/account_voucher/static/description/account_sc_06.png differ
diff --git a/addons/account_voucher/static/description/bazile.png b/addons/account_voucher/static/description/bazile.png
new file mode 100644
index 00000000000..30f37e70b4a
Binary files /dev/null and b/addons/account_voucher/static/description/bazile.png differ
diff --git a/addons/account_voucher/static/src/img/icon.png b/addons/account_voucher/static/description/icon.png
similarity index 100%
rename from addons/account_voucher/static/src/img/icon.png
rename to addons/account_voucher/static/description/icon.png
diff --git a/addons/account_voucher/static/description/index.html b/addons/account_voucher/static/description/index.html
new file mode 100644
index 00000000000..a363291f12e
--- /dev/null
+++ b/addons/account_voucher/static/description/index.html
@@ -0,0 +1,140 @@
+
+
+ Create and send professional looking invoices & get paid
+ online. It automatically integrates with other apps to bill
+ automatically based on your activities.
+
+ Send invoices directly to your clients in just a click. The
+ invoice is automatically attached to the email as a PDF file.
+
+
+
+
+
+
+
+
+
+
+
Get Paid Faster
+
Electronic invoicing and automated follow-ups
+
+
+
+
+
+
+Get paid online with paypal or other payment processing service. Get rid of
+the stress of having to constantly remind your debtors. Simply set-up and
+automate follow-ups to get paid quickly.
+
+
+
+
+
+
+
+
+
Connect Your Bank Accounts
+
+
+Import your bank statements and reconcile them in just a few clicks. Prepare
+payment orders based on your supplier invoices and payment terms.
+
+
+
+
+
+
+
+
+
+
+
+
Analyse Your Sales & Costs
+
+
+
+
+
+Get direct access to key information with dynamic and customizable dashboards.
+Analyse your invoicing by product, customer, salesperson, etc.
+
+
+
+
+
+
+
+
Integration With Other Apps
+
+
+Bill automatically based on sales orders, delivery orders, contracts or on time and
+material. Define recurrencies to produce recurring invoice automatically.
+
+
+
+
+
+
+
+
+
+
+
+
Many companies already enjoy it
+
Hear what they have to say !
+
+
+
+
+ OpenERP allowed us to automate sending 10.000 invoices per month.
+
+
+
+
Примечание: если вы не запрашивали сброс пароля, просто проигнорируйте "
+"данное письмо
"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/js/auth_signup.js:111
#, python-format
msgid "Please enter a name."
-msgstr ""
+msgstr "Пожалуйста, введите имя"
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_users
msgid "Users"
-msgstr ""
+msgstr "Пользователи"
#. module: auth_signup
#: field:res.partner,signup_url:0
@@ -146,7 +155,7 @@ msgstr "Пожалуйста, введите имя пользователя."
#. module: auth_signup
#: selection:res.users,state:0
msgid "Active"
-msgstr ""
+msgstr "Активен"
#. module: auth_signup
#: code:addons/auth_signup/res_users.py:269
@@ -155,39 +164,41 @@ msgid ""
"Cannot send email: no outgoing email server configured.\n"
"You can configure it under Settings/General Settings."
msgstr ""
+"Невозможно отправить email: не настроены сервера исходящей почты.\n"
+"Вы можете настроить их в меню Настройки/Общие настройки"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:12
#, python-format
msgid "Username"
-msgstr ""
+msgstr "Имя пользователя"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:8
#, python-format
msgid "Name"
-msgstr ""
+msgstr "Имя"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/js/auth_signup.js:170
#, python-format
msgid "Please enter a username or email address."
-msgstr ""
+msgstr "Пожалуйста, введите имя пользователя или адрес эл. почты."
#. module: auth_signup
#: selection:res.users,state:0
msgid "Resetting Password"
-msgstr ""
+msgstr "Переустановка пароля"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:13
#, python-format
msgid "Username (Email)"
-msgstr ""
+msgstr "Имя пользователя (Email)"
#. module: auth_signup
#: field:res.partner,signup_expiration:0
@@ -198,13 +209,15 @@ msgstr ""
#: help:base.config.settings,auth_signup_reset_password:0
msgid "This allows users to trigger a password reset from the Login page."
msgstr ""
+"Это позволяет пользователям запросить сброс пароля со страницы входа в "
+"систему."
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:22
#, python-format
msgid "Log in"
-msgstr ""
+msgstr "Вход"
#. module: auth_signup
#: field:res.partner,signup_valid:0
@@ -222,7 +235,7 @@ msgstr ""
#: code:addons/auth_signup/static/src/js/auth_signup.js:170
#, python-format
msgid "Login"
-msgstr ""
+msgstr "Вход"
#. module: auth_signup
#. openerp-web
@@ -236,7 +249,7 @@ msgstr ""
#: code:addons/auth_signup/static/src/js/auth_signup.js:120
#, python-format
msgid "Passwords do not match; please retype them."
-msgstr ""
+msgstr "Пароли не совпадают; пожалуйста, введите их заново."
#. module: auth_signup
#. openerp-web
@@ -244,7 +257,7 @@ msgstr ""
#: code:addons/auth_signup/static/src/js/auth_signup.js:167
#, python-format
msgid "No database selected !"
-msgstr ""
+msgstr "Не выбрана база данных!"
#. module: auth_signup
#: view:res.users:0
@@ -254,14 +267,14 @@ msgstr ""
#. module: auth_signup
#: field:base.config.settings,auth_signup_reset_password:0
msgid "Enable password reset from Login page"
-msgstr ""
+msgstr "Включить сброс пароля со страницы входа"
#. module: auth_signup
#. openerp-web
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:27
#, python-format
msgid "Back to Login"
-msgstr ""
+msgstr "Вернуться к странице входа"
#. module: auth_signup
#. openerp-web
@@ -273,7 +286,7 @@ msgstr ""
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_partner
msgid "Partner"
-msgstr ""
+msgstr "Партнер"
#. module: auth_signup
#: field:res.partner,signup_token:0
diff --git a/addons/auth_signup/i18n/vi.po b/addons/auth_signup/i18n/vi.po
new file mode 100644
index 00000000000..a79bbcb7bb4
--- /dev/null
+++ b/addons/auth_signup/i18n/vi.po
@@ -0,0 +1,288 @@
+# Vietnamese 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-06-27 06:52+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Vietnamese \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-28 05:42+0000\n"
+"X-Generator: Launchpad (build 16681)\n"
+
+#. module: auth_signup
+#: field:res.partner,signup_type:0
+msgid "Signup Token Type"
+msgstr "Loại mã đăng ký"
+
+#. module: auth_signup
+#: field:base.config.settings,auth_signup_uninvited:0
+msgid "Allow external users to sign up"
+msgstr "Cho phép người dùng bên ngoài đăng ký."
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:19
+#, python-format
+msgid "Confirm Password"
+msgstr "Xác nhận mật khẩu"
+
+#. module: auth_signup
+#: help:base.config.settings,auth_signup_uninvited:0
+msgid "If unchecked, only invited users may sign up."
+msgstr "Nếu không chọn, chỉ những người được mời mới được đăng ký."
+
+#. 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:266
+#, python-format
+msgid "Cannot send email: user has no email address."
+msgstr "Không thể gửi email: người dùng không có địa chỉ email"
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:27
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:31
+#, python-format
+msgid "Reset password"
+msgstr "Đặt lại mật khẩu"
+
+#. module: auth_signup
+#: field:base.config.settings,auth_signup_template_user_id:0
+msgid "Template user for new users created through signup"
+msgstr "Mẫu người dùng sử dụng khi đăng ký"
+
+#. module: auth_signup
+#: model:email.template,subject:auth_signup.reset_password_email
+msgid "Password reset"
+msgstr "Quên mật khẩu"
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:120
+#, python-format
+msgid "Please enter a password and confirm it."
+msgstr "Vui lòng nhập mật khẩu và xác nhận nó"
+
+#. 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:26
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:29
+#, 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 "Trạng thái"
+
+#. 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.
"
+msgstr ""
+"\n"
+"\\n\n"
+"
Bạn có một yêu cầu reset mật khẩu từ tài khoản OpenERPA gắn với email "
+"này.
\\n\n"
+"\\n\n"
+"
Bạn có thể thay đổi mật khẩu thông qua đường dẫn này.
\\n\n"
+"\\n\n"
+"
Lưu ý: Nếu đây không phải chủ ý của bạn. Bạn có thể bỏ qua email này.
"
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:114
+#, python-format
+msgid "Please enter a name."
+msgstr "Xin nhập tên."
+
+#. module: auth_signup
+#: model:ir.model,name:auth_signup.model_res_users
+msgid "Users"
+msgstr "Người dùng"
+
+#. module: auth_signup
+#: field:res.partner,signup_url:0
+msgid "Signup URL"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:117
+#, python-format
+msgid "Please enter a username."
+msgstr ""
+
+#. module: auth_signup
+#: selection:res.users,state:0
+msgid "Active"
+msgstr ""
+
+#. module: auth_signup
+#: code:addons/auth_signup/res_users.py:270
+#, python-format
+msgid ""
+"Cannot send email: no outgoing email server configured.\n"
+"You can configure it under Settings/General Settings."
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:12
+#, python-format
+msgid "Username"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:8
+#, python-format
+msgid "Name"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:173
+#, python-format
+msgid "Please enter a username or email address."
+msgstr ""
+
+#. module: auth_signup
+#: selection:res.users,state:0
+msgid "Resetting Password"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:13
+#, python-format
+msgid "Username (Email)"
+msgstr ""
+
+#. module: auth_signup
+#: field:res.partner,signup_expiration:0
+msgid "Signup Expiration"
+msgstr ""
+
+#. module: auth_signup
+#: help:base.config.settings,auth_signup_reset_password:0
+msgid "This allows users to trigger a password reset from the Login page."
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:25
+#, python-format
+msgid "Log in"
+msgstr ""
+
+#. module: auth_signup
+#: field:res.partner,signup_valid:0
+msgid "Signup Token is Valid"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:111
+#: code:addons/auth_signup/static/src/js/auth_signup.js:114
+#: code:addons/auth_signup/static/src/js/auth_signup.js:117
+#: code:addons/auth_signup/static/src/js/auth_signup.js:120
+#: code:addons/auth_signup/static/src/js/auth_signup.js:123
+#: code:addons/auth_signup/static/src/js/auth_signup.js:170
+#: code:addons/auth_signup/static/src/js/auth_signup.js:173
+#, python-format
+msgid "Login"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:97
+#, python-format
+msgid "Invalid signup token"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:123
+#, python-format
+msgid "Passwords do not match; please retype them."
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:111
+#: code:addons/auth_signup/static/src/js/auth_signup.js:170
+#, python-format
+msgid "No database selected !"
+msgstr ""
+
+#. module: auth_signup
+#: view:res.users:0
+msgid "Reset Password"
+msgstr ""
+
+#. module: auth_signup
+#: field:base.config.settings,auth_signup_reset_password:0
+msgid "Enable password reset from Login page"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:30
+#, python-format
+msgid "Back to Login"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:22
+#, python-format
+msgid "Sign up"
+msgstr ""
+
+#. module: auth_signup
+#: model:ir.model,name:auth_signup.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: auth_signup
+#: field:res.partner,signup_token:0
+msgid "Signup Token"
+msgstr ""
diff --git a/addons/auth_signup/i18n/zh_CN.po b/addons/auth_signup/i18n/zh_CN.po
index aa8d9f952c1..497b872997f 100644
--- a/addons/auth_signup/i18n/zh_CN.po
+++ b/addons/auth_signup/i18n/zh_CN.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:05+0000\n"
-"PO-Revision-Date: 2013-04-16 04:33+0000\n"
-"Last-Translator: Key \n"
+"PO-Revision-Date: 2013-07-02 08:11+0000\n"
+"Last-Translator: DWXXX \n"
"Language-Team: Chinese (Simplified) \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-17 05:15+0000\n"
-"X-Generator: Launchpad (build 16567)\n"
+"X-Launchpad-Export-Date: 2013-07-03 05:14+0000\n"
+"X-Generator: Launchpad (build 16692)\n"
#. module: auth_signup
#: field:res.partner,signup_type:0
@@ -29,7 +29,7 @@ msgstr "允许外部用户登录"
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/xml/auth_signup.xml:16
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:19
#, python-format
msgid "Confirm Password"
msgstr "确认密码"
@@ -37,7 +37,7 @@ msgstr "确认密码"
#. module: auth_signup
#: help:base.config.settings,auth_signup_uninvited:0
msgid "If unchecked, only invited users may sign up."
-msgstr ""
+msgstr "如果不勾选,只有被邀请用户才能注册。"
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_base_config_settings
@@ -45,15 +45,15 @@ msgid "base.config.settings"
msgstr "base.config.settings"
#. module: auth_signup
-#: code:addons/auth_signup/res_users.py:265
+#: code:addons/auth_signup/res_users.py:266
#, python-format
msgid "Cannot send email: user has no email address."
-msgstr ""
+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
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:27
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:31
#, python-format
msgid "Reset password"
msgstr "重设密码"
@@ -70,7 +70,7 @@ msgstr "重置密码"
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:117
+#: code:addons/auth_signup/static/src/js/auth_signup.js:120
#, python-format
msgid "Please enter a password and confirm it."
msgstr "请输入密码并确认。"
@@ -78,12 +78,12 @@ msgstr "请输入密码并确认。"
#. module: auth_signup
#: view:res.users:0
msgid "Send an email to the user to (re)set their password."
-msgstr ""
+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
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:29
#, python-format
msgid "Sign Up"
msgstr "注册"
@@ -119,10 +119,10 @@ msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:111
+#: code:addons/auth_signup/static/src/js/auth_signup.js:114
#, python-format
msgid "Please enter a name."
-msgstr ""
+msgstr "请输入名字"
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_users
@@ -136,10 +136,10 @@ msgstr "注册 URL"
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:114
+#: code:addons/auth_signup/static/src/js/auth_signup.js:117
#, python-format
msgid "Please enter a username."
-msgstr ""
+msgstr "请输入您的用户名"
#. module: auth_signup
#: selection:res.users,state:0
@@ -147,7 +147,7 @@ msgid "Active"
msgstr "启用"
#. module: auth_signup
-#: code:addons/auth_signup/res_users.py:269
+#: code:addons/auth_signup/res_users.py:270
#, python-format
msgid ""
"Cannot send email: no outgoing email server configured.\n"
@@ -170,10 +170,10 @@ msgstr "姓名"
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:170
+#: code:addons/auth_signup/static/src/js/auth_signup.js:173
#, python-format
msgid "Please enter a username or email address."
-msgstr ""
+msgstr "请输入用户名和邮件地址"
#. module: auth_signup
#: selection:res.users,state:0
@@ -199,7 +199,7 @@ msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/xml/auth_signup.xml:22
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:25
#, python-format
msgid "Log in"
msgstr "登录"
@@ -211,35 +211,35 @@ msgstr "注册令牌( Token )是有效的"
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:108
#: code:addons/auth_signup/static/src/js/auth_signup.js:111
#: code:addons/auth_signup/static/src/js/auth_signup.js:114
#: code:addons/auth_signup/static/src/js/auth_signup.js:117
#: code:addons/auth_signup/static/src/js/auth_signup.js:120
-#: code:addons/auth_signup/static/src/js/auth_signup.js:167
+#: code:addons/auth_signup/static/src/js/auth_signup.js:123
#: code:addons/auth_signup/static/src/js/auth_signup.js:170
+#: code:addons/auth_signup/static/src/js/auth_signup.js:173
#, python-format
msgid "Login"
msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:94
+#: code:addons/auth_signup/static/src/js/auth_signup.js:97
#, python-format
msgid "Invalid signup token"
msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:120
+#: code:addons/auth_signup/static/src/js/auth_signup.js:123
#, python-format
msgid "Passwords do not match; please retype them."
msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/js/auth_signup.js:108
-#: code:addons/auth_signup/static/src/js/auth_signup.js:167
+#: code:addons/auth_signup/static/src/js/auth_signup.js:111
+#: code:addons/auth_signup/static/src/js/auth_signup.js:170
#, python-format
msgid "No database selected !"
msgstr ""
@@ -256,7 +256,7 @@ msgstr ""
#. module: auth_signup
#. openerp-web
-#: code:addons/auth_signup/static/src/xml/auth_signup.xml:27
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:30
#, python-format
msgid "Back to Login"
msgstr "返回登录页面"
@@ -266,12 +266,12 @@ msgstr "返回登录页面"
#: code:addons/auth_signup/static/src/xml/auth_signup.xml:22
#, python-format
msgid "Sign up"
-msgstr ""
+msgstr "注册"
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_partner
msgid "Partner"
-msgstr "业务伙伴"
+msgstr "合作伙伴"
#. module: auth_signup
#: field:res.partner,signup_token:0
diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py
index f4a985280ac..891837f8813 100644
--- a/addons/auth_signup/res_users.py
+++ b/addons/auth_signup/res_users.py
@@ -23,6 +23,7 @@ import random
from urllib import urlencode
from urlparse import urljoin
+from openerp.addons.base.ir.ir_mail_server import MailDeliveryException
from openerp.osv import osv, fields
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools.safe_eval import safe_eval
@@ -55,19 +56,22 @@ class res_partner(osv.Model):
def _get_signup_url_for_action(self, cr, uid, ids, action='login', view_type=None, menu_id=None, res_id=None, model=None, context=None):
""" generate a signup url for the given partner ids and action, possibly overriding
the url state components (menu_id, id, view_type) """
+ if context is None:
+ context= {}
res = dict.fromkeys(ids, False)
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
for partner in self.browse(cr, uid, ids, context):
# when required, make sure the partner has a valid signup token
- if context and context.get('signup_valid') and not partner.user_ids:
+ if context.get('signup_valid') and not partner.user_ids:
self.signup_prepare(cr, uid, [partner.id], context=context)
partner.refresh()
# the parameters to encode for the query and fragment part of url
query = {'db': cr.dbname}
- fragment = {'action': action, 'type': partner.signup_type}
+ signup_type = context.get('signup_force_type_in_url', partner.signup_type or '')
+ fragment = {'action': action, 'type': signup_type}
- if partner.signup_token:
+ if partner.signup_token and signup_type:
fragment['token'] = partner.signup_token
elif partner.user_ids:
fragment['db'] = cr.dbname
@@ -103,6 +107,9 @@ class res_partner(osv.Model):
def action_signup_prepare(self, cr, uid, ids, context=None):
return self.signup_prepare(cr, uid, ids, context=context)
+ def signup_cancel(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'signup_token': False, 'signup_type': False, 'signup_expiration': False}, context=context)
+
def signup_prepare(self, cr, uid, ids, signup_type="signup", expiration=False, context=None):
""" generate a new token for the partners with the given validity, if necessary
:param expiration: the expiration datetime of the token (string, optional)
@@ -202,7 +209,7 @@ class res_users(osv.Model):
})
if partner.company_id:
values['company_id'] = partner.company_id.id
- values['company_ids'] = [(6,0,[partner.company_id.id])]
+ values['company_ids'] = [(6, 0, [partner.company_id.id])]
self._signup_create_user(cr, uid, values, context=context)
else:
# no token, sign up an external user
@@ -259,25 +266,26 @@ class res_users(osv.Model):
pass
if not bool(template):
template = self.pool.get('ir.model.data').get_object(cr, uid, 'auth_signup', 'reset_password_email')
- mail_obj = self.pool.get('mail.mail')
assert template._name == 'email.template'
for user in self.browse(cr, uid, ids, context):
if not user.email:
raise osv.except_osv(_("Cannot send email: user has no email address."), user.name)
- mail_id = self.pool.get('email.template').send_mail(cr, uid, template.id, user.id, True, context=context)
- mail_state = mail_obj.read(cr, uid, mail_id, ['state'], context=context)
-
- if mail_state and mail_state['state'] == 'exception':
- raise self.pool.get('res.config.settings').get_config_warning(cr, _("Cannot send email: no outgoing email server configured.\nYou can configure it under %(menu:base_setup.menu_general_configuration)s."), context)
- else:
- return True
+ try:
+ self.pool.get('email.template').send_mail(cr, uid, template.id, user.id, force_send=True, raise_exception=True, context=context)
+ except Exception:
+ raise
def create(self, cr, uid, values, context=None):
+ if context is None:
+ context = {}
# overridden to automatically invite user to sign up
user_id = super(res_users, self).create(cr, uid, values, context=context)
user = self.browse(cr, uid, user_id, context=context)
- if context and context.get('reset_password') and user.email:
- ctx = dict(context, create_user=True)
- self.action_reset_password(cr, uid, [user.id], context=ctx)
+ if user.email and not context.get('no_reset_password'):
+ context.update({'create_user': True})
+ try:
+ self.action_reset_password(cr, uid, [user.id], context=context)
+ except MailDeliveryException:
+ self.pool.get('res.partner').signup_cancel(cr, uid, [user.partner_id.id], context=context)
return user_id
diff --git a/addons/auth_signup/res_users_view.xml b/addons/auth_signup/res_users_view.xml
index 28f66eb101d..60c419db737 100644
--- a/addons/auth_signup/res_users_view.xml
+++ b/addons/auth_signup/res_users_view.xml
@@ -31,9 +31,11 @@
diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js
index bbaf907c625..b825d683099 100644
--- a/addons/auth_signup/static/src/js/auth_signup.js
+++ b/addons/auth_signup/static/src/js/auth_signup.js
@@ -7,7 +7,7 @@ openerp.auth_signup = function(instance) {
var self = this;
this.signup_enabled = false;
this.reset_password_enabled = false;
- return this._super().then(function() {
+ return this._super().always(function() {
// Switches the login box to the select mode whith mode == [default|signup|reset]
self.on('change:login_mode', self, function() {
@@ -57,14 +57,14 @@ openerp.auth_signup = function(instance) {
self.signup_enabled = result.signup;
self.reset_password_enabled = result.reset_password;
if (!self.signup_enabled || self.$("form input[name=login]").val()){
- self.set('login_mode', 'default');
+ self.set('login_mode', self.params.type || 'default');
} else {
self.set('login_mode', 'signup');
}
});
} else {
// TODO: support multiple database mode
- self.set('login_mode', 'default');
+ self.set('login_mode', self.params.type || 'default');
}
});
},
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 9d7d4d34ac4..3497255fa76 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -50,6 +50,7 @@ class base_action_rule(osv.osv):
_name = 'base.action.rule'
_description = 'Action Rules'
+ _order = 'sequence'
_columns = {
'name': fields.char('Rule Name', size=64, required=True),
@@ -61,7 +62,11 @@ class base_action_rule(osv.osv):
help="When unchecked, the rule is hidden and will not be executed."),
'sequence': fields.integer('Sequence',
help="Gives the sequence order when displaying a list of rules."),
+ 'kind': fields.selection(
+ [('on_create', 'On Creation'), ('on_write', 'On Update'), ('on_time', 'Based on Timed Condition')],
+ string='When to Run'),
'trg_date_id': fields.many2one('ir.model.fields', string='Trigger Date',
+ help="When should the condition be triggered. If present, will be checked by the scheduler. If empty, will be checked at creation and update.",
domain="[('model_id', '=', model_id), ('ttype', 'in', ('date', 'datetime'))]"),
'trg_date_range': fields.integer('Delay after trigger date',
help="Delay after the trigger date." \
@@ -78,10 +83,10 @@ class base_action_rule(osv.osv):
ondelete='restrict',
domain="[('model_id', '=', model_id.model)]",
help="If present, this condition must be satisfied before the update of the record."),
- 'filter_id': fields.many2one('ir.filters', string='After Update Filter',
+ 'filter_id': fields.many2one('ir.filters', string='Filter',
ondelete='restrict',
domain="[('model_id', '=', model_id.model)]",
- help="If present, this condition must be satisfied after the update of the record."),
+ help="If present, this condition must be satisfied before executing the action rule."),
'last_run': fields.datetime('Last Run', readonly=1),
}
@@ -90,7 +95,15 @@ class base_action_rule(osv.osv):
'trg_date_range_type': 'day',
}
- _order = 'sequence'
+ def onchange_kind(self, cr, uid, ids, kind, context=None):
+ clear_fields = []
+ if kind == 'on_create':
+ clear_fields = ['filter_pre_id', 'trg_date_id', 'trg_date_range', 'trg_date_range_type']
+ elif kind == 'on_write':
+ clear_fields = ['trg_date_id', 'trg_date_range', 'trg_date_range_type']
+ elif kind == 'on_time':
+ clear_fields = ['filter_pre_id']
+ return {'value': dict.fromkeys(clear_fields, False)}
def _filter(self, cr, uid, action, action_filter, record_ids, context=None):
""" filter the list record_ids that satisfy the action filter """
@@ -105,14 +118,7 @@ class base_action_rule(osv.osv):
def _process(self, cr, uid, action, record_ids, context=None):
""" process the given action on the records """
- # execute server actions
model = self.pool[action.model_id.model]
- if action.server_action_ids:
- server_action_ids = map(int, action.server_action_ids)
- for record in model.browse(cr, uid, record_ids, context):
- action_server_obj = self.pool.get('ir.actions.server')
- ctx = dict(context, active_model=model._name, active_ids=[record.id], active_id=record.id)
- action_server_obj.run(cr, uid, server_action_ids, context=ctx)
# modify records
values = {}
@@ -127,13 +133,21 @@ class base_action_rule(osv.osv):
follower_ids = map(int, action.act_followers)
model.message_subscribe(cr, uid, record_ids, follower_ids, context=context)
+ # execute server actions
+ if action.server_action_ids:
+ server_action_ids = map(int, action.server_action_ids)
+ for record in model.browse(cr, uid, record_ids, context):
+ action_server_obj = self.pool.get('ir.actions.server')
+ ctx = dict(context, active_model=model._name, active_ids=[record.id], active_id=record.id)
+ action_server_obj.run(cr, uid, server_action_ids, context=ctx)
+
return True
def _wrap_create(self, old_create, model):
""" Return a wrapper around `old_create` calling both `old_create` and
`_process`, in that order.
"""
- def wrapper(cr, uid, vals, context=None):
+ def create(cr, uid, vals, context=None):
# avoid loops or cascading actions
if context and context.get('action'):
return old_create(cr, uid, vals, context=context)
@@ -141,8 +155,8 @@ class base_action_rule(osv.osv):
context = dict(context or {}, action=True)
new_id = old_create(cr, uid, vals, context=context)
- # as it is a new record, we do not consider the actions that have a prefilter
- action_dom = [('model', '=', model), ('trg_date_id', '=', False), ('filter_pre_id', '=', False)]
+ # retrieve the action rules to run on creation
+ action_dom = [('model', '=', model), ('kind', '=', 'on_create')]
action_ids = self.search(cr, uid, action_dom, context=context)
# check postconditions, and execute actions on the records that satisfy them
@@ -151,13 +165,13 @@ class base_action_rule(osv.osv):
self._process(cr, uid, action, [new_id], context=context)
return new_id
- return wrapper
+ return create
def _wrap_write(self, old_write, model):
""" Return a wrapper around `old_write` calling both `old_write` and
`_process`, in that order.
"""
- def wrapper(cr, uid, ids, vals, context=None):
+ def write(cr, uid, ids, vals, context=None):
# avoid loops or cascading actions
if context and context.get('action'):
return old_write(cr, uid, ids, vals, context=context)
@@ -165,8 +179,8 @@ class base_action_rule(osv.osv):
context = dict(context or {}, action=True)
ids = [ids] if isinstance(ids, (int, long, str)) else ids
- # retrieve the action rules to possibly execute
- action_dom = [('model', '=', model), ('trg_date_id', '=', False)]
+ # retrieve the action rules to run on update
+ action_dom = [('model', '=', model), ('kind', '=', 'on_write')]
action_ids = self.search(cr, uid, action_dom, context=context)
actions = self.browse(cr, uid, action_ids, context=context)
@@ -185,7 +199,7 @@ class base_action_rule(osv.osv):
self._process(cr, uid, action, post_ids, context=context)
return True
- return wrapper
+ return write
def _register_hook(self, cr, ids=None):
""" Wrap the methods `create` and `write` of the models specified by
@@ -224,8 +238,8 @@ class base_action_rule(osv.osv):
def _check(self, cr, uid, automatic=False, use_new_cursor=False, context=None):
""" This Function is called by scheduler. """
context = context or {}
- # retrieve all the action rules that have a trg_date_id and no precondition
- action_dom = [('trg_date_id', '!=', False), ('filter_pre_id', '=', False)]
+ # retrieve all the action rules to run based on a timed condition
+ action_dom = [('kind', '=', 'on_time')]
action_ids = self.search(cr, uid, action_dom, context=context)
for action in self.browse(cr, uid, action_ids, context=context):
now = datetime.now()
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 5eaaf08dad4..c2262adde39 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -26,24 +26,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
- Select a filter or a timer as condition. An action rule is checked when you create or modify the "Related Document Model". The precondition filter is checked right before the modification while the postcondition filter is checked after the modification. A precondition filter will therefore not work during a creation.
- To create a new filter:
- - Go to your "Related Document Model" page and set the filter parameters in the "Search" view (Example of filter based on Leads/Opportunities: Creation Date "is equal to" 01/01/2012)
- - In this same "Search" view, select the menu "Save Current Filter", enter the name (Ex: Create the 01/01/2012) and add the option "Share with all users"
+
+ Select when the action must be run, and add filters and/or timing conditions.
+
+ In order to create a new filter:
+
+
Go to your "Related Document Model" page and set the filter parameters in the "Search" view (Example of filter based on Leads/Opportunities: Creation Date "is equal to" 01/01/2012)
+
In this same "Search" view, select the menu "Save Current Filter", enter the name (Ex: Create the 01/01/2012) and add the option "Share with all users"
\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
+"X-Generator: Launchpad (build 16677)\n"
+
+#. module: base_gengo
+#: view:res.company:0
+msgid "Comments for Translator"
+msgstr ""
+
+#. module: base_gengo
+#: field:ir.translation,job_id:0
+msgid "Gengo Job ID"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:114
+#, python-format
+msgid "This language is not supported by the Gengo translation services."
+msgstr ""
+
+#. module: base_gengo
+#: field:res.company,gengo_comment:0
+msgid "Comments"
+msgstr "ความคิดเห็น"
+
+#. module: base_gengo
+#: field:res.company,gengo_private_key:0
+msgid "Gengo Private Key"
+msgstr ""
+
+#. module: base_gengo
+#: model:ir.model,name:base_gengo.model_base_gengo_translations
+msgid "base.gengo.translations"
+msgstr "base.gengo.translations"
+
+#. module: base_gengo
+#: help:res.company,gengo_auto_approve:0
+msgid "Jobs are Automatically Approved by Gengo."
+msgstr ""
+
+#. module: base_gengo
+#: field:base.gengo.translations,lang_id:0
+msgid "Language"
+msgstr "ภาษา"
+
+#. module: base_gengo
+#: field:ir.translation,gengo_comment:0
+msgid "Comments & Activity Linked to Gengo"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:124
+#, python-format
+msgid "Gengo Sync Translation (Response)"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:72
+#, python-format
+msgid ""
+"Gengo `Public Key` or `Private Key` are missing. Enter your Gengo "
+"authentication parameters under `Settings > Companies > Gengo Parameters`."
+msgstr ""
+
+#. module: base_gengo
+#: selection:ir.translation,gengo_translation:0
+msgid "Translation By Machine"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:155
+#, python-format
+msgid ""
+"%s\n"
+"\n"
+"--\n"
+" Commented on %s by %s."
+msgstr ""
+
+#. module: base_gengo
+#: field:ir.translation,gengo_translation:0
+msgid "Gengo Translation Service Level"
+msgstr ""
+
+#. module: base_gengo
+#: constraint:ir.translation:0
+msgid ""
+"The Gengo translation service selected is not supported for this language."
+msgstr ""
+
+#. module: base_gengo
+#: selection:ir.translation,gengo_translation:0
+msgid "Standard"
+msgstr ""
+
+#. module: base_gengo
+#: help:ir.translation,gengo_translation:0
+msgid ""
+"You can select here the service level you want for an automatic translation "
+"using Gengo."
+msgstr ""
+
+#. module: base_gengo
+#: field:base.gengo.translations,restart_send_job:0
+msgid "Restart Sending Job"
+msgstr ""
+
+#. module: base_gengo
+#: view:ir.translation:0
+msgid "To Approve In Gengo"
+msgstr ""
+
+#. module: base_gengo
+#: view:res.company:0
+msgid "Private Key"
+msgstr ""
+
+#. module: base_gengo
+#: view:res.company:0
+msgid "Public Key"
+msgstr ""
+
+#. module: base_gengo
+#: field:res.company,gengo_public_key:0
+msgid "Gengo Public Key"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:123
+#, python-format
+msgid "Gengo Sync Translation (Request)"
+msgstr ""
+
+#. module: base_gengo
+#: view:ir.translation:0
+msgid "Translations"
+msgstr ""
+
+#. module: base_gengo
+#: field:res.company,gengo_auto_approve:0
+msgid "Auto Approve Translation ?"
+msgstr ""
+
+#. module: base_gengo
+#: model:ir.actions.act_window,name:base_gengo.action_wizard_base_gengo_translations
+#: model:ir.ui.menu,name:base_gengo.menu_action_wizard_base_gengo_translations
+msgid "Gengo: Manual Request of Translation"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/ir_translation.py:62
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:109
+#, python-format
+msgid "Gengo Authentication Error"
+msgstr ""
+
+#. module: base_gengo
+#: model:ir.model,name:base_gengo.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: base_gengo
+#: view:ir.translation:0
+msgid ""
+"Note: If the translation state is 'In Progress', it means that the "
+"translation has to be approved to be uploaded in this system. You are "
+"supposed to do that directly by using your Gengo Account"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:82
+#, python-format
+msgid ""
+"Gengo connection failed with this message:\n"
+"``%s``"
+msgstr ""
+
+#. module: base_gengo
+#: view:res.company:0
+msgid "Gengo Parameters"
+msgstr ""
+
+#. module: base_gengo
+#: view:base.gengo.translations:0
+msgid "Send"
+msgstr ""
+
+#. module: base_gengo
+#: selection:ir.translation,gengo_translation:0
+msgid "Ultra"
+msgstr ""
+
+#. module: base_gengo
+#: model:ir.model,name:base_gengo.model_ir_translation
+msgid "ir.translation"
+msgstr ""
+
+#. module: base_gengo
+#: view:ir.translation:0
+msgid "Gengo Translation Service"
+msgstr ""
+
+#. module: base_gengo
+#: selection:ir.translation,gengo_translation:0
+msgid "Pro"
+msgstr ""
+
+#. module: base_gengo
+#: view:base.gengo.translations:0
+msgid "Gengo Request Form"
+msgstr ""
+
+#. module: base_gengo
+#: code:addons/base_gengo/wizard/base_gengo_translations.py:114
+#, python-format
+msgid "Warning"
+msgstr ""
+
+#. module: base_gengo
+#: help:res.company,gengo_comment:0
+msgid ""
+"This comment will be automatically be enclosed in each an every request sent "
+"to Gengo"
+msgstr ""
+
+#. module: base_gengo
+#: view:base.gengo.translations:0
+msgid "Cancel"
+msgstr ""
+
+#. module: base_gengo
+#: view:base.gengo.translations:0
+msgid "or"
+msgstr ""
diff --git a/addons/base_import/static/csv/o2m_customers_contacts.csv b/addons/base_import/static/csv/o2m_customers_contacts.csv
new file mode 100644
index 00000000000..9a2411b2bee
--- /dev/null
+++ b/addons/base_import/static/csv/o2m_customers_contacts.csv
@@ -0,0 +1,9 @@
+Name,Is a company,Related company,Address type,Customer,Supplier,Street,ZIP,City,State,Country
+Aurora Shelves,1,,,1,0,25 Pacific Road,95101,San José,CA,United States
+Roger Martins,0,Aurora Shelves,Invoice,1,0,27 Pacific Road,95102,San José,CA,United States
+House Sales Direct,1,,,1,0,104 Saint Mary Avenue,94059,Redwood,CA,United States
+Yvan Holiday,0,House Sales Direct,Default,1,0,104 Saint Mary Avenue,94060,Redwood,CA,United States
+Jack Unsworth,0,House Sales Direct,Invoice,1,0,227 Jackson Road,94061,Redwood,CA,United States
+Michael Mason,0,,,1,0,16 5th Avenue,94104,San Francisco,CA,United States
+International Wood,1,,,1,0,748 White House Boulevard,20004,Washington,DC,United States
+Sharon Pecker,0,International Wood,Invoice,1,0,755 White House Boulevard,20005,Washington,DC,United States
diff --git a/addons/base_import/static/csv/o2m_suppliers_contacts.csv b/addons/base_import/static/csv/o2m_suppliers_contacts.csv
deleted file mode 100644
index 6c7be9037b8..00000000000
--- a/addons/base_import/static/csv/o2m_suppliers_contacts.csv
+++ /dev/null
@@ -1,8 +0,0 @@
-Name,Address type,Street,City,Country,Tags,Supplier,Customer,Is a company,Companies that refers to partner / Parent company
-Wood y Wood Pecker,,"Snow Street, 25",Kainuu,Finland,Supplier,1,0,1,
-Roger Pecker,Default,"Snow Street, 27",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
-Sharon Pecker,Delivery,"Snow Street, 28",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
-Thomas Pecker,Contact,"Snow Street, 27",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
-Vicking Direct,,"Atonium Street, 45a",Brussels,Belgium,Supplier,1,0,1,
-Yvan Holiday,Invoice,"Atonium Street, 45b",Brussels,Belgium,Supplier,1,0,0,Vicking Direct
-Jack Unsworth,Contact,"Atonium Street, 45a",Brussels,Belgium,Supplier,1,0,0,Vicking Direct
diff --git a/addons/base_import/static/lib/select2/README.md b/addons/base_import/static/lib/select2/README.md
old mode 100755
new mode 100644
diff --git a/addons/base_import/static/lib/select2/select2.css b/addons/base_import/static/lib/select2/select2.css
old mode 100755
new mode 100644
diff --git a/addons/base_import/static/lib/select2/select2.js b/addons/base_import/static/lib/select2/select2.js
old mode 100755
new mode 100644
diff --git a/addons/base_import/static/lib/select2/spinner.gif b/addons/base_import/static/lib/select2/spinner.gif
old mode 100755
new mode 100644
diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml
index c8b2b2c63dd..97bf3e66f7a 100644
--- a/addons/base_import/static/src/xml/import.xml
+++ b/addons/base_import/static/src/xml/import.xml
@@ -229,8 +229,8 @@
orders with their respective purchase order lines:
Purchase orders with their respective purchase order lines
The following CSV file shows how to import
- suppliers and their respective contacts
- Suppliers and their respective contacts
+ customers and their respective contacts
+ Customers and their respective contacts
diff --git a/addons/base_report_designer/base_report_designer_installer.xml b/addons/base_report_designer/base_report_designer_installer.xml
index 99898f5a703..61b7fbc4c1d 100644
--- a/addons/base_report_designer/base_report_designer_installer.xml
+++ b/addons/base_report_designer/base_report_designer_installer.xml
@@ -14,9 +14,13 @@
-
+
+
+
+
+
+
-
diff --git a/addons/base_report_designer/openerp_sxw2rml/openerp_sxw2rml.py b/addons/base_report_designer/openerp_sxw2rml/openerp_sxw2rml.py
old mode 100644
new mode 100755
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/About.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/About.py
index 43b452b82e2..9fb6cd11219 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/About.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/About.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
from com.sun.star.task import XJobExecutor
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/AddAttachment.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/AddAttachment.py
index ba69174ffc6..2dce1750e34 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/AddAttachment.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/AddAttachment.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 os
import uno
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Change.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Change.py
index b85a9d9bb06..e0b66780e8b 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Change.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Change.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
import unohelper
@@ -72,7 +49,7 @@ class Change( unohelper.Base, XJobExecutor ):
'XML-RPC': 'http://',
'XML-RPC secure': 'https://',
'NET-RPC': 'socket://',
- }
+ }
host=port=protocol=''
if docinfo.getUserFieldValue(0):
m = re.match('^(http[s]?://|socket://)([\w.\-]+):(\d{1,5})$', docinfo.getUserFieldValue(0) or '')
@@ -80,7 +57,7 @@ class Change( unohelper.Base, XJobExecutor ):
port = m.group(3)
protocol = m.group(1)
if protocol:
- for (key, value) in self.protocol.iteritems():
+ for (key, value) in self.protocol.iteritems():
if value==protocol:
protocol=key
break
@@ -102,7 +79,7 @@ class Change( unohelper.Base, XJobExecutor ):
self.win.addButton( 'btnNext', -2, -5, 30, 15, 'Next', actionListenerProc = self.btnNext_clicked )
self.win.addButton( 'btnCancel', -2 - 30 - 5 ,-5, 30, 15, 'Cancel', actionListenerProc = self.btnCancel_clicked )
-
+
for i in self.protocol.keys():
self.lstProtocol.addItem(i,self.lstProtocol.getItemCount() )
self.win.doModalDialog( "lstProtocol", protocol)
@@ -110,27 +87,27 @@ class Change( unohelper.Base, XJobExecutor ):
def btnNext_clicked(self, oActionEvent):
global url
aVal=''
- #aVal= Fetature used
+ #aVal= Fetature used
try:
url = self.protocol[self.win.getListBoxSelectedItem("lstProtocol")]+self.win.getEditText("txtHost")+":"+self.win.getEditText("txtPort")
self.sock=RPCSession(url)
desktop=getDesktop()
doc = desktop.getCurrentComponent()
- docinfo=doc.getDocumentInfo()
+ docinfo=doc.getDocumentInfo()
docinfo.setUserFieldValue(0,url)
res=self.sock.listdb()
self.win.endExecute()
ServerParameter(aVal,url)
except :
- import traceback,sys
+ import traceback,sys
info = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
- self.logobj.log_write('ServerParameter', LOG_ERROR, info)
+ self.logobj.log_write('ServerParameter', LOG_ERROR, info)
ErrorDialog("Connection to server is fail. Please check your Server Parameter.", "", "Error!")
self.win.endExecute()
-
+
def btnCancel_clicked(self,oActionEvent):
self.win.endExecute()
-
+
if __name__<>"package" and __name__=="__main__":
Change(None)
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertBracesToField.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertBracesToField.py
index c1fa8b22a85..17cc25687b1 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertBracesToField.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertBracesToField.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import unohelper
import string
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertFieldsToBraces.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertFieldsToBraces.py
index ffa88a8cd06..b8abcb1dc6c 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertFieldsToBraces.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ConvertFieldsToBraces.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import unohelper
@@ -81,7 +57,7 @@ class ConvertFieldsToBraces( unohelper.Base, XJobExecutor ):
if __name__<>"package":
ConvertFieldsToBraces(None)
else:
- g_ImplementationHelper.addImplementation( ConvertFieldsToBraces, "org.openoffice.openerp.report.convertFB", ("com.sun.star.task.Job",),)
+ g_ImplementationHelper.addImplementation( ConvertFieldsToBraces, "org.openoffice.openerp.report.convertFB", ("com.sun.star.task.Job",),)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ExportToRML.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ExportToRML.py
index d2605ce73e4..a12becdc68c 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ExportToRML.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ExportToRML.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 os
import uno
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Expression.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Expression.py
index 9e3b175b67b..896a5954c7d 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Expression.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Expression.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Fields.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Fields.py
index 90f85e57a0d..8ed4d2c25e8 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Fields.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Fields.py
@@ -1,50 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/LoginTest.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/LoginTest.py
index 85059d7712c..11c74555447 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/LoginTest.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/LoginTest.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 .
-#
-#
-##############################################################################
+#############################################################################
+
if __name__<>"package":
from ServerParameter import *
from lib.gui import *
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ModifyExistingReport.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ModifyExistingReport.py
index bc7d439c76d..ef1d3548a6e 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ModifyExistingReport.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ModifyExistingReport.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/NewReport.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/NewReport.py
index 138c68b690e..3c6316d9fdb 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/NewReport.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/NewReport.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Repeatln.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Repeatln.py
index f5e0972d2dd..b6edaecdc44 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Repeatln.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Repeatln.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/SendToServer.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/SendToServer.py
index 7e83910a427..dbd0a51d66d 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/SendToServer.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/SendToServer.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
@@ -201,7 +177,7 @@ class SendtoServer(unohelper.Base, XJobExecutor):
if self.win.getListBoxSelectedItem("lstResourceType")=='OpenOffice':
params['report_type']=file_type
self.sock.execute(database, uid, self.password, 'ir.actions.report.xml', 'write', int(docinfo.getUserFieldValue(2)), params)
-
+
# Call upload_report as the *last* step, as it will call register_all() and cause the report service
# to be loaded - which requires all the data to be correct in the database
self.sock.execute(database, uid, self.password, 'ir.actions.report.xml', 'upload_report', int(docinfo.getUserFieldValue(2)),base64.encodestring(data),file_type,{})
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ServerParameter.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ServerParameter.py
index c399634bfe5..b09b02699b0 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ServerParameter.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/ServerParameter.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
import unohelper
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Translation.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Translation.py
index 05f81a5c5b2..132882e0932 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Translation.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/Translation.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 uno
import string
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/__init__.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/__init__.py
index 0ccd1c9d011..d7f93351fac 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/__init__.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/__init__.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 Expression
import lib
import Fields
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/compile_all.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/compile_all.py
index 4740c61b178..897f9abd00c 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/compile_all.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/compile_all.py
@@ -1,49 +1,26 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 compileall
compileall.compile_dir('package')
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/actions.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/actions.py
index 8511bb8343d..cf82d0e1a76 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/actions.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/actions.py
@@ -1,47 +1,23 @@
##########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 .
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
##############################################################################
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/error.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/error.py
index cb86f5f429a..f44404eaa16 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/error.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/error.py
@@ -1,47 +1,23 @@
##########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 .
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
##############################################################################
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/functions.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/functions.py
index 1d10f0f6a4c..52af0821790 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/functions.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/functions.py
@@ -1,47 +1,23 @@
##########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 .
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
##############################################################################
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/gui.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/gui.py
index d75469ca658..92b5ab750ca 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/gui.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/gui.py
@@ -1,47 +1,23 @@
##########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
+# This library 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
+# Lesser General Public License for more details.
#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 .
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+# See: http://www.gnu.org/licenses/lgpl.html
#
##############################################################################
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/rpc.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/rpc.py
index 5d6f8ca6dbc..e0176bfec62 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/rpc.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/lib/rpc.py
@@ -61,8 +61,8 @@ class RPCSession(object):
protocol = m.group(1)
if not m:
return -1
- if protocol == 'http://' or protocol == 'http://':
- self.gateway = XMLRPCGateway(host, port, 'http')
+ if protocol == 'http://' or protocol == 'https://':
+ self.gateway = XMLRPCGateway(host, port, protocol[:-3])
elif protocol == 'socket://':
self.gateway = NETRPCGateway(host, port)
diff --git a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/modify.py b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/modify.py
index 60edbc71d96..f8d90c30d75 100644
--- a/addons/base_report_designer/plugin/openerp_report_designer/bin/script/modify.py
+++ b/addons/base_report_designer/plugin/openerp_report_designer/bin/script/modify.py
@@ -1,49 +1,25 @@
-##########################################################################
+#########################################################################
#
-# Portions of this file are under the following copyright and license:
+# Copyright (c) 2003-2004 Danny Brewer d29583@groovegarden.com
+# Copyright (C) 2004-2010 OpenERP SA ().
#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
#
-# Copyright (c) 2003-2004 Danny Brewer
-# d29583@groovegarden.com
+# This library 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
+# Lesser General Public License for more details.
#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# This library 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
-# Lesser General Public License for more details.
+# See: http://www.gnu.org/licenses/lgpl.html
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# See: http://www.gnu.org/licenses/lgpl.html
-#
-#
-# and other portions are under the following copyright and license:
-#
-#
-# OpenERP, Open Source Management Solution>..
-# Copyright (C) 2004-2010 OpenERP SA ().
-#
-# 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 re
import uno
diff --git a/addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip b/addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip
index 7d03f45dbb4..238f9d19671 100644
Binary files a/addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip and b/addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip differ
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_setup/i18n/ru.po b/addons/base_setup/i18n/ru.po
index bfc0807f019..ab26ce496d6 100644
--- a/addons/base_setup/i18n/ru.po
+++ b/addons/base_setup/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-12-28 10:09+0000\n"
+"PO-Revision-Date: 2013-06-17 10:30+0000\n"
"Last-Translator: Chertykov Denis \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-06-18 05:46+0000\n"
+"X-Generator: Launchpad (build 16673)\n"
#. module: base_setup
#: view:sale.config.settings:0
@@ -41,6 +41,8 @@ msgstr "base.config.settings"
msgid ""
"Use external authentication providers, sign in with google, facebook, ..."
msgstr ""
+"Использовать внешние сервисы аутентификации, например, вход через google, "
+"facebook, ..."
#. module: base_setup
#: view:sale.config.settings:0
@@ -68,7 +70,7 @@ msgstr "Участник"
#. module: base_setup
#: view:base.config.settings:0
msgid "Portal access"
-msgstr ""
+msgstr "Доступ к порталу"
#. module: base_setup
#: view:base.config.settings:0
@@ -90,7 +92,7 @@ msgstr "Общие настройки"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
msgid "Donor"
-msgstr ""
+msgstr "Спонсор"
#. module: base_setup
#: view:base.config.settings:0
@@ -145,7 +147,7 @@ msgstr "res_config_contents"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Customer Features"
-msgstr ""
+msgstr "Свойства заказчика"
#. module: base_setup
#: view:base.config.settings:0
@@ -155,7 +157,7 @@ msgstr "Импорт / Экспорт"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Sale Features"
-msgstr ""
+msgstr "Свойства продаж"
#. module: base_setup
#: field:sale.config.settings,module_plugin_outlook:0
@@ -192,6 +194,9 @@ 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 ""
+"Когда вы создаете новый контакт (человека или компанию), у вас есть "
+"возможность загрузить из LinkedIn всю информацию о нем (адреса, фотографии и "
+"т.д.)"
#. module: base_setup
#: help:base.config.settings,module_multi_company:0
@@ -200,6 +205,9 @@ msgid ""
"companies.\n"
" This installs the module multi_company."
msgstr ""
+"Работать в режиме Мульти-компании, с соответствующими правами доступа между "
+"компаниями.\n"
+" Будет установлен модуль multi_company."
#. module: base_setup
#: view:base.config.settings:0
@@ -208,6 +216,9 @@ msgid ""
"You can\n"
" launch the OpenERP Server with the option"
msgstr ""
+"Публичный портал доступен только при использовании одной базы данных. Вы "
+"можете\n"
+" запустить сервер OpenERP с этой опцией"
#. module: base_setup
#: view:base.config.settings:0
@@ -215,11 +226,13 @@ msgid ""
"You will find more options in your company details: address for the header "
"and footer, overdue payments texts, etc."
msgstr ""
+"Больше опций вы можете найти в настройках компании: адреса для "
+"верхнего/нижнего колонтитула, тексты для просроченных платежей и т.д."
#. 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,11 +251,19 @@ msgid ""
"projects,\n"
" etc."
msgstr ""
+"Когда вы отправляете заказчику документы\n"
+" (прайсы, счета), для их получения он "
+"сможет\n"
+" войти на портал, где так же сможет "
+"прочитать\n"
+" новости вашей компании, узнать "
+"обновления по\n"
+" его проектам и т.д."
#. module: base_setup
#: model:ir.model,name:base_setup.model_base_setup_terminology
msgid "base.setup.terminology"
-msgstr ""
+msgstr "base.setup.terminology"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -252,7 +273,7 @@ msgstr "Клиент"
#. module: base_setup
#: help:base.config.settings,module_portal_anonymous:0
msgid "Enable the public part of openerp, openerp becomes a public website."
-msgstr ""
+msgstr "Включая публичную часть, openerp становится общедоступным сайтом."
#. module: base_setup
#: help:sale.config.settings,module_plugin_thunderbird:0
@@ -274,13 +295,13 @@ msgstr "Контрагент"
#. module: base_setup
#: model:ir.actions.act_window,name:base_setup.action_partner_terminology_config_form
msgid "Use another word to say \"Customer\""
-msgstr ""
+msgstr "Использовать другое слово вместо \"Заказчик\""
#. module: base_setup
#: model:ir.actions.act_window,name:base_setup.action_sale_config
#: view:sale.config.settings:0
msgid "Configure Sales"
-msgstr ""
+msgstr "Настройки продаж"
#. module: base_setup
#: help:sale.config.settings,module_plugin_outlook:0
@@ -297,12 +318,12 @@ msgstr ""
#. module: base_setup
#: view:base.config.settings:0
msgid "Options"
-msgstr ""
+msgstr "Настройки"
#. module: base_setup
#: field:base.config.settings,module_portal:0
msgid "Activate the customer portal"
-msgstr ""
+msgstr "Включить клиентский портал"
#. module: base_setup
#: view:base.config.settings:0
@@ -315,32 +336,32 @@ msgstr ""
#. module: base_setup
#: field:base.config.settings,module_share:0
msgid "Allow documents sharing"
-msgstr ""
+msgstr "Разрешить совместный доступ к документам"
#. module: base_setup
#: view:base.config.settings:0
msgid "(company news, jobs, contact form, etc.)"
-msgstr ""
+msgstr "(новости компании, вакансии, форма обратной связи т.д.)"
#. module: base_setup
#: field:base.config.settings,module_portal_anonymous:0
msgid "Activate the public portal"
-msgstr ""
+msgstr "Включить публичный портал"
#. module: base_setup
#: view:base.config.settings:0
msgid "Configure outgoing email servers"
-msgstr ""
+msgstr "Настроить сервер(а) исходящей почты"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Social Network Integration"
-msgstr ""
+msgstr "Интеграция с социальными сетями"
#. module: base_setup
#: help:base.config.settings,module_portal:0
msgid "Give your customers access to their documents."
-msgstr ""
+msgstr "Разрешить заказчикам доступ к своим документам"
#. module: base_setup
#: view:base.config.settings:0
@@ -352,23 +373,23 @@ msgstr "Отмена"
#: view:base.config.settings:0
#: view:sale.config.settings:0
msgid "Apply"
-msgstr ""
+msgstr "Применить"
#. module: base_setup
#: view:base.setup.terminology:0
msgid "Specify Your Terminology"
-msgstr ""
+msgstr "Определить терминологию"
#. module: base_setup
#: view:base.config.settings:0
#: view:sale.config.settings:0
msgid "or"
-msgstr ""
+msgstr "или"
#. module: base_setup
#: view:base.config.settings:0
msgid "Configure your company data"
-msgstr ""
+msgstr "Настроить информацию о компании"
#~ msgid "City"
#~ msgstr "Город"
diff --git a/addons/base_setup/res_config.py b/addons/base_setup/res_config.py
index 33c5aa863bf..6b8578bbf47 100644
--- a/addons/base_setup/res_config.py
+++ b/addons/base_setup/res_config.py
@@ -36,6 +36,8 @@ class base_config_settings(osv.osv_memory):
help="""Enable the public part of openerp, openerp becomes a public website."""),
'module_auth_oauth': fields.boolean('Use external authentication providers, sign in with google, facebook, ...'),
'module_base_import': fields.boolean("Allow users to import data from CSV files"),
+ 'module_google_drive': fields.boolean('Attach Google documents to any record',
+ help="""This installs the module google_docs."""),
}
def open_company(self, cr, uid, ids, context=None):
diff --git a/addons/base_setup/res_config_view.xml b/addons/base_setup/res_config_view.xml
index 9e026184c9d..73685be95df 100644
--- a/addons/base_setup/res_config_view.xml
+++ b/addons/base_setup/res_config_view.xml
@@ -31,7 +31,7 @@
-
+
@@ -81,6 +81,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/addons/base_status/base_state.py b/addons/base_status/base_state.py
index b856bbd74ad..3fe59ecbd21 100644
--- a/addons/base_status/base_state.py
+++ b/addons/base_status/base_state.py
@@ -104,7 +104,7 @@ class base_state(object):
if parent_id.change_responsible and parent_id.user_id:
data['user_id'] = parent_id.user_id.id
else:
- raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
+ raise osv.except_osv(_('Error!'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
self.write(cr, uid, [case.id], data, context=context)
case.case_escalate_send_note(parent_id, context=context)
return True
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/ru.po b/addons/base_status/i18n/ru.po
index 546f2772af3..2dab7ceaf31 100644
--- a/addons/base_status/i18n/ru.po
+++ b/addons/base_status/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-12-28 10:04+0000\n"
+"PO-Revision-Date: 2013-06-05 07:16+0000\n"
"Last-Translator: Chertykov Denis \n"
"Language-Team: Russian \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:52+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-06 05:21+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
#. module: base_status
#: code:addons/base_status/base_state.py:107
@@ -27,13 +27,13 @@ msgstr "Ошибка !"
#: code:addons/base_status/base_state.py:166
#, python-format
msgid "%s has been opened."
-msgstr ""
+msgstr "%s было открыто."
#. module: base_status
#: code:addons/base_status/base_state.py:199
#, python-format
msgid "%s has been renewed."
-msgstr ""
+msgstr "%s было обновлено."
#. module: base_status
#: code:addons/base_status/base_stage.py:210
@@ -55,13 +55,13 @@ msgstr ""
#: code:addons/base_status/base_state.py:193
#, python-format
msgid "%s is now pending."
-msgstr ""
+msgstr "%s сейчас в ожидании."
#. module: base_status
#: code:addons/base_status/base_state.py:187
#, python-format
msgid "%s has been canceled."
-msgstr ""
+msgstr "%s было отменено."
#. module: base_status
#: code:addons/base_status/base_stage.py:210
@@ -70,9 +70,11 @@ msgid ""
"You are already at the top level of your sales-team category.\n"
"Therefore you cannot escalate furthermore."
msgstr ""
+"Вы уже на высшем уровне категории вашей команды продаж.\n"
+"Поэтому вы не можете обострить."
#. module: base_status
#: code:addons/base_status/base_state.py:181
#, python-format
msgid "%s has been closed."
-msgstr ""
+msgstr "%s было закрыто."
diff --git a/addons/base_status/i18n/sv.po b/addons/base_status/i18n/sv.po
new file mode 100644
index 00000000000..eb1b42e6a53
--- /dev/null
+++ b/addons/base_status/i18n/sv.po
@@ -0,0 +1,79 @@
+# Swedish 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-07-08 15:10+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Swedish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-07-09 05:16+0000\n"
+"X-Generator: Launchpad (build 16696)\n"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:107
+#, python-format
+msgid "Error !"
+msgstr "Fel !"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:166
+#, python-format
+msgid "%s has been opened."
+msgstr "%s har öppnats."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:199
+#, python-format
+msgid "%s has been renewed."
+msgstr "%s har förnyats."
+
+#. module: base_status
+#: code:addons/base_status/base_stage.py:210
+#, python-format
+msgid "Error!"
+msgstr "Fel!"
+
+#. 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 ""
+"Du kan inte eskalera längre, du har nått toppen för denna säljlags-kategori."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:193
+#, python-format
+msgid "%s is now pending."
+msgstr "%s är nu pågående."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:187
+#, python-format
+msgid "%s has been canceled."
+msgstr "%s har avbrutits."
+
+#. 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 ""
+"Du har nått översta nivån för din säljlagskategori.\n"
+"Det går därför inte att eskalera ytterligare."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:181
+#, python-format
+msgid "%s has been closed."
+msgstr "%s har stängts."
diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py
index e7501334997..52db18b7307 100644
--- a/addons/base_vat/base_vat.py
+++ b/addons/base_vat/base_vat.py
@@ -83,6 +83,8 @@ class res_partner(osv.osv):
Check the VAT number depending of the country.
http://sima-pc.com/nif.php
'''
+ if not ustr(country_code).encode('utf-8').isalpha():
+ return False
check_func_name = 'check_vat_' + country_code
check_func = getattr(self, check_func_name, None) or \
getattr(vatnumber, check_func_name, None)
diff --git a/addons/board/__openerp__.py b/addons/board/__openerp__.py
index e699e091176..87771b2f518 100644
--- a/addons/board/__openerp__.py
+++ b/addons/board/__openerp__.py
@@ -31,7 +31,7 @@ Lets the user create a custom dashboard.
Allows users to create custom dashboard.
""",
'author': 'OpenERP SA',
- 'depends': ['base'],
+ 'depends': ['base', 'web'],
'data': [
'security/ir.model.access.csv',
'board_view.xml',
diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js
index 3489b686e1b..4f50d2281fe 100644
--- a/addons/board/static/src/js/dashboard.js
+++ b/addons/board/static/src/js/dashboard.js
@@ -344,7 +344,7 @@ instance.board.AddToDashboard = instance.web.search.Input.extend({
},
load_data:function(){
var board = new instance.web.Model('board.board');
- return board.call('list');
+ return board.call('list', [board.context()]);
},
_x:function() {
if (!instance.webclient) { return $.Deferred().reject(); }
diff --git a/addons/claim_from_delivery/i18n/ru.po b/addons/claim_from_delivery/i18n/ru.po
index 253e824d1e2..ffcf8fc2781 100644
--- a/addons/claim_from_delivery/i18n/ru.po
+++ b/addons/claim_from_delivery/i18n/ru.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: 2010-09-30 06:47+0000\n"
+"PO-Revision-Date: 2013-06-05 07:11+0000\n"
"Last-Translator: Chertykov Denis \n"
"Language-Team: Russian \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-06-06 05:21+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
#. module: claim_from_delivery
#: view:stock.picking.out:0
msgid "Claims"
-msgstr ""
+msgstr "Рекламации"
#. module: claim_from_delivery
#: model:res.request.link,name:claim_from_delivery.request_link_claim_from_delivery
msgid "Delivery Order"
-msgstr ""
+msgstr "Заказ доставки"
#. module: claim_from_delivery
#: model:ir.actions.act_window,name:claim_from_delivery.action_claim_from_delivery
msgid "Claim From Delivery"
-msgstr ""
+msgstr "Рекламация по доставке"
#~ msgid "Claim from delivery"
#~ msgstr "Претензия из доставки"
diff --git a/addons/claim_from_delivery/i18n/vi.po b/addons/claim_from_delivery/i18n/vi.po
new file mode 100644
index 00000000000..f308bafb1ea
--- /dev/null
+++ b/addons/claim_from_delivery/i18n/vi.po
@@ -0,0 +1,33 @@
+# Vietnamese 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-06-30 16:10+0000\n"
+"Last-Translator: Hung Tran \n"
+"Language-Team: Vietnamese \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-07-01 05:14+0000\n"
+"X-Generator: Launchpad (build 16692)\n"
+
+#. module: claim_from_delivery
+#: view:stock.picking.out:0
+msgid "Claims"
+msgstr "Các khiếu nại"
+
+#. module: claim_from_delivery
+#: model:res.request.link,name:claim_from_delivery.request_link_claim_from_delivery
+msgid "Delivery Order"
+msgstr ""
+
+#. module: claim_from_delivery
+#: model:ir.actions.act_window,name:claim_from_delivery.action_claim_from_delivery
+msgid "Claim From Delivery"
+msgstr ""
diff --git a/addons/contacts/i18n/ko.po b/addons/contacts/i18n/ko.po
new file mode 100644
index 00000000000..19e46f9e0b0
--- /dev/null
+++ b/addons/contacts/i18n/ko.po
@@ -0,0 +1,37 @@
+# Korean 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-06-28 09:32+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Korean \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-30 05:56+0000\n"
+"X-Generator: Launchpad (build 16692)\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 ""
+
+#. module: contacts
+#: model:ir.actions.act_window,name:contacts.action_contacts
+#: model:ir.ui.menu,name:contacts.menu_contacts
+msgid "Contacts"
+msgstr "연락처"
diff --git a/addons/contacts/i18n/th.po b/addons/contacts/i18n/th.po
new file mode 100644
index 00000000000..a75ecac2237
--- /dev/null
+++ b/addons/contacts/i18n/th.po
@@ -0,0 +1,37 @@
+# Thai 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-15 07:10+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Thai
\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 ""
+
+#. module: contacts
+#: model:ir.actions.act_window,name:contacts.action_contacts
+#: model:ir.ui.menu,name:contacts.menu_contacts
+msgid "Contacts"
+msgstr ""
diff --git a/addons/contacts/i18n/vi.po b/addons/contacts/i18n/vi.po
new file mode 100644
index 00000000000..d404d947fe2
--- /dev/null
+++ b/addons/contacts/i18n/vi.po
@@ -0,0 +1,45 @@
+# Vietnamese 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-06-27 16:47+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Vietnamese \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-28 05:42+0000\n"
+"X-Generator: Launchpad (build 16681)\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"
+" Nhấn để thêm liên lạc vào sổ địa chỉ.\n"
+"
\n"
+" OpenERP giúp bạn theo dõi các hoạt động liên quan tới\n"
+" một khách hàng; thảo luận, lịch sử cơ hội kinh doanh,\n"
+" tài liệu v.v....\n"
+"
\n"
+" "
+
+#. module: contacts
+#: model:ir.actions.act_window,name:contacts.action_contacts
+#: model:ir.ui.menu,name:contacts.menu_contacts
+msgid "Contacts"
+msgstr "Liên hệ"
diff --git a/addons/contacts/static/src/img/icon.png b/addons/contacts/static/description/icon.png
similarity index 100%
rename from addons/contacts/static/src/img/icon.png
rename to addons/contacts/static/description/icon.png
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..e7ab7df27ea 100644
--- a/addons/crm/__openerp__.py
+++ b/addons/crm/__openerp__.py
@@ -81,8 +81,6 @@ Dashboard for CRM will include:
'crm_lead_view.xml',
'crm_lead_menu.xml',
- 'crm_case_section_view.xml',
-
'crm_meeting_menu.xml',
'crm_phonecall_view.xml',
@@ -97,6 +95,9 @@ Dashboard for CRM will include:
'board_crm_view.xml',
'res_config_view.xml',
+ 'base_partner_merge_view.xml',
+
+ 'crm_case_section_view.xml',
],
'demo': [
'crm_demo.xml',
@@ -120,7 +121,8 @@ Dashboard for CRM will include:
'static/src/css/crm.css'
],
'js': [
- 'static/src/js/crm.js'
+ 'static/lib/sparkline/jquery.sparkline.js',
+ 'static/src/js/crm_case_section.js',
],
'installable': True,
'application': True,
diff --git a/addons/crm/base_partner_merge.py b/addons/crm/base_partner_merge.py
new file mode 100644
index 00000000000..42e1ab7c7ec
--- /dev/null
+++ b/addons/crm/base_partner_merge.py
@@ -0,0 +1,769 @@
+#!/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
+
+import openerp
+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'),
+ 'dst_partner_id': fields.many2one('res.partner', string='Destination Contact'),
+
+ '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"),
+ }
+
+ def default_get(self, cr, uid, fields, context=None):
+ if context is None:
+ context = {}
+ res = super(MergePartnerAutomatic, self).default_get(cr, uid, fields, context)
+ if context.get('active_model') == 'res.partner' and context.get('active_ids'):
+ partner_ids = context['active_ids']
+ res['state'] = 'selection'
+ res['partner_ids'] = partner_ids
+ res['dst_partner_id'] = self._get_ordered_partner(cr, uid, partner_ids, context=context)[-1].id
+ return res
+
+ _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, openerp.SUPERUSER_ID, domain, context=context)
+ return proxy.write(cr, openerp.SUPERUSER_ID, 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, openerp.SUPERUSER_ID, domain, context=context)
+
+ for record in proxy.browse(cr, openerp.SUPERUSER_ID, 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, openerp.SUPERUSER_ID, domain, context=context)
+ values = {
+ record.name: 'res.partner,%d' % dst_partner.id,
+ }
+ proxy_model.write(cr, openerp.SUPERUSER_ID, 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') and not isinstance(field, fields.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, dst_partner=None, 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
+
+ if len(partner_ids) > 3:
+ raise osv.except_osv(_('Error'), _("For safety reasons, you cannot merge more than 3 contacts together. You can re-open the wizard several times if needed."))
+
+ if openerp.SUPERUSER_ID != uid and len(set(partner.email for partner in proxy.browse(cr, uid, partner_ids, context=context))) > 1:
+ raise osv.except_osv(_('Error'), _("All contacts must have the same email. Only the Administrator can merge contacts with different emails."))
+
+ if dst_partner and dst_partner.id in partner_ids:
+ src_partners = proxy.browse(cr, uid, [id for id in partner_ids if id != dst_partner.id], context=context)
+ else:
+ ordered_partners = self._get_ordered_partner(cr, uid, partner_ids, context)
+ dst_partner = ordered_partners[-1]
+ src_partners = ordered_partners[:-1]
+ _logger.info("dst_partner: %s", dst_partner.id)
+
+ if openerp.SUPERUSER_ID != uid and self._model_is_installed(cr, uid, 'account.move.line', context=context) and \
+ self.pool.get('account.move.line').search(cr, openerp.SUPERUSER_ID, [('partner_id', 'in', [partner.id for partner in src_partners])], context=context):
+ raise osv.except_osv(_('Error'), _("Only the destination contact may be linked to existing Journal Items. Please ask the Administrator if you need to merge several contacts linked to existing Journal Items."))
+
+ 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('(uid = %s) merged the partners %r with %s', uid, list(map(operator.attrgetter('id'), src_partners)), dst_partner.id)
+ dst_partner.message_post(body='%s %s'%(_("Merged with the following partners:"), ", ".join('%s<%s>(ID %s)' % (p.name, p.email or 'n/a', p.id) for p in src_partners)))
+
+ 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(cr, uid, this, context)
+
+ def _get_ordered_partner(self, cr, uid, partner_ids, context=None):
+ partners = self.pool.get('res.partner').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)
+ return ordered_partners
+
+ def _next_screen(self, cr, uid, this, context=None):
+ 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)],
+ 'dst_partner_id': self._get_ordered_partner(cr, uid, current_partner_ids, context)[-1].id,
+ '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(cr, uid, this, context)
+
+ 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(cr, uid, this, context)
+
+ 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, this.dst_partner_id, context=context)
+
+ if this.current_line_id:
+ this.current_line_id.unlink()
+
+ return self._next_screen(cr, uid, this, context)
+
+ 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..8ce0b5fd99f
--- /dev/null
+++ b/addons/crm/base_partner_merge_view.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+ Deduplicate Contacts
+ base.partner.merge.automatic.wizard
+ form
+ form
+ new
+ {'active_test': False}
+
+
+
+
+
+ base.partner.merge.automatic.wizard.form
+ base.partner.merge.automatic.wizard
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/crm.py b/addons/crm/crm.py
index 7b6fe02afa8..d1194508b71 100644
--- a/addons/crm/crm.py
+++ b/addons/crm/crm.py
@@ -19,13 +19,12 @@
#
##############################################################################
-import base64
-import time
-from lxml import etree
+from datetime import date, datetime
+from dateutil import relativedelta
+
+from openerp import tools
from openerp.osv import fields
from openerp.osv import osv
-from openerp import tools
-from openerp.tools.translate import _
MAX_LEVEL = 15
AVAILABLE_STATES = [
@@ -106,10 +105,57 @@ class crm_case_section(osv.osv):
_inherit = "mail.thread"
_description = "Sales Teams"
_order = "complete_name"
+ # number of periods for lead/opportunities/... tracking in salesteam kanban dashboard/kanban view
+ _period_number = 5
def get_full_name(self, cr, uid, ids, field_name, arg, context=None):
return dict(self.name_get(cr, uid, ids, context=context))
+ def __get_bar_values(self, cr, uid, obj, domain, read_fields, value_field, groupby_field, context=None):
+ """ Generic method to generate data for bar chart values using SparklineBarWidget.
+ This method performs obj.read_group(cr, uid, domain, read_fields, groupby_field).
+
+ :param obj: the target model (i.e. crm_lead)
+ :param domain: the domain applied to the read_group
+ :param list read_fields: the list of fields to read in the read_group
+ :param str value_field: the field used to compute the value of the bar slice
+ :param str groupby_field: the fields used to group
+
+ :return list section_result: a list of dicts: [
+ { 'value': (int) bar_column_value,
+ 'tootip': (str) bar_column_tooltip,
+ }
+ ]
+ """
+ month_begin = date.today().replace(day=1)
+ section_result = [{
+ 'value': 0,
+ 'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'),
+ } for i in range(self._period_number - 1, -1, -1)]
+ group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
+ for group in group_obj:
+ group_begin_date = datetime.strptime(group['__domain'][0][2], tools.DEFAULT_SERVER_DATE_FORMAT)
+ month_delta = relativedelta.relativedelta(month_begin, group_begin_date)
+ section_result[self._period_number - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group_begin_date.strftime('%B')}
+ return section_result
+
+ def _get_opportunities_data(self, cr, uid, ids, field_name, arg, context=None):
+ """ Get opportunities-related data for salesteam kanban view
+ monthly_open_leads: number of open lead during the last months
+ monthly_planned_revenue: planned revenu of opportunities during the last months
+ """
+ obj = self.pool.get('crm.lead')
+ res = dict.fromkeys(ids, False)
+ month_begin = date.today().replace(day=1)
+ groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+ for id in ids:
+ res[id] = dict()
+ lead_domain = [('type', '=', 'lead'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)]
+ res[id]['monthly_open_leads'] = self.__get_bar_values(cr, uid, obj, lead_domain, ['create_date'], 'create_date_count', 'create_date', context=context)
+ opp_domain = [('type', '=', 'opportunity'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)]
+ res[id]['monthly_planned_revenue'] = self.__get_bar_values(cr, uid, obj, opp_domain, ['planned_revenue', 'create_date'], 'planned_revenue', 'create_date', context=context)
+ return res
+
_columns = {
'name': fields.char('Sales Team', size=64, required=True, translate=True),
'complete_name': fields.function(get_full_name, type='char', size=256, readonly=True, store=True),
@@ -129,15 +175,16 @@ class crm_case_section(osv.osv):
'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True,
help="The email address associated with this team. New emails received will automatically "
"create new leads assigned to the team."),
- 'open_lead_ids': fields.one2many('crm.lead', 'section_id',
- string='Open Leads', readonly=True,
- domain=['&', ('type', '!=', 'opportunity'), ('state', 'not in', ['done', 'cancel'])]),
- 'open_opportunity_ids': fields.one2many('crm.lead', 'section_id',
- string='Open Opportunities', readonly=True,
- domain=['&', '|', ('type', '=', 'opportunity'), ('type', '=', 'both'), ('state', 'not in', ['done', 'cancel'])]),
'color': fields.integer('Color Index'),
'use_leads': fields.boolean('Leads',
- help="This enables the management of leads in the sales team. Otherwise the sales team manages only opportunities."),
+ help="The first contact you get with a potential customer is a lead you qualify before converting it into a real business opportunity. Check this box to manage leads in this sales team."),
+
+ 'monthly_open_leads': fields.function(_get_opportunities_data,
+ type="string", readonly=True, multi='_get_opportunities_data',
+ string='Open Leads per Month'),
+ 'monthly_planned_revenue': fields.function(_get_opportunities_data,
+ type="string", readonly=True, multi='_get_opportunities_data',
+ string='Planned Revenue per Month')
}
def _get_stage_common(self, cr, uid, context):
@@ -175,17 +222,13 @@ class crm_case_section(osv.osv):
return res
def create(self, cr, uid, vals, context=None):
- mail_alias = self.pool.get('mail.alias')
- if not vals.get('alias_id'):
- alias_name = vals.pop('alias_name', None) or vals.get('name') # prevent errors during copy()
- alias_id = mail_alias.create_unique_alias(cr, uid,
- {'alias_name': alias_name},
- model_name="crm.lead",
- context=context)
- vals['alias_id'] = alias_id
- res = super(crm_case_section, self).create(cr, uid, vals, context)
- mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type': 'lead'}}, context)
- return res
+ if context is None:
+ context = {}
+ create_context = dict(context, alias_model_name='crm.lead', alias_parent_model_name=self._name)
+ section_id = super(crm_case_section, self).create(cr, uid, vals, context=create_context)
+ section = self.browse(cr, uid, section_id, context=context)
+ self.pool.get('mail.alias').write(cr, uid, [section.alias_id.id], {'alias_parent_thread_id': section_id, 'alias_defaults': {'section_id': section_id, 'type': 'lead'}}, context=context)
+ return section_id
def unlink(self, cr, uid, ids, context=None):
# Cascade-delete mail aliases as well, as they should not exist without the sales team.
diff --git a/addons/crm/crm_action_rule_demo.xml b/addons/crm/crm_action_rule_demo.xml
index bf1f7d4082f..7204f666db5 100644
--- a/addons/crm/crm_action_rule_demo.xml
+++ b/addons/crm/crm_action_rule_demo.xml
@@ -26,6 +26,7 @@ Description: [[object.description]]
Set Auto Reminder on leads which are not open since 5 days.1
+ on_time5
@@ -54,12 +55,10 @@ object.write({'section_id': sales_team.id})
Set Auto Followers on leads which are urgent and come from USA.2
+ on_create
-
-
- 0
- minutes
+
diff --git a/addons/crm/crm_case_section_view.xml b/addons/crm/crm_case_section_view.xml
index c788872b47e..c957311b47f 100644
--- a/addons/crm/crm_case_section_view.xml
+++ b/addons/crm/crm_case_section_view.xml
@@ -43,8 +43,7 @@
{
'search_default_section_id': [active_id],
- 'search_default_new': 1,
- 'search_default_open': 1,
+ 'search_default_assigned_to_me': 1,
'default_section_id': active_id,
'stage_type': 'opportunity',
'default_type': 'opportunity',
@@ -79,12 +78,12 @@
-
-
+
+
-
- Sales
- Sales
+ Direct Sales
+ DMTrue
+ info
diff --git a/addons/crm/crm_demo.xml b/addons/crm/crm_demo.xml
index 203193dc3bc..2858250e86a 100644
--- a/addons/crm/crm_demo.xml
+++ b/addons/crm/crm_demo.xml
@@ -7,27 +7,13 @@
- Sales Marketing Department
- SMD
-
+ Indirect Sales
+ IM
- Support Department
+ MarketingSPD
-
-
-
-
- Direct Marketing
- DM
-
-
-
-
- Online Support
- OS
-
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 61e8c75cea8..af02e3be1bf 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -19,12 +19,12 @@
#
##############################################################################
-from openerp.addons.base_status.base_stage import base_stage
import crm
from datetime import datetime
from operator import itemgetter
-from openerp.osv import fields, osv
+from openerp.osv import fields, osv, orm
import time
+from openerp import SUPERUSER_ID
from openerp import tools
from openerp.tools.translate import _
from openerp.tools import html2plaintext
@@ -67,7 +67,7 @@ CRM_LEAD_PENDING_STATES = (
crm.AVAILABLE_STATES[4][0], # Pending
)
-class crm_lead(base_stage, format_address, osv.osv):
+class crm_lead(format_address, osv.osv):
""" CRM Lead Case """
_name = "crm.lead"
_description = "Lead/Opportunity"
@@ -76,12 +76,12 @@ class crm_lead(base_stage, format_address, osv.osv):
_track = {
'state': {
- 'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'new',
- 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
- 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'cancel',
+ 'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj.state in ['new', 'draft'],
+ 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj.state == 'done',
+ 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.state == 'cancel',
},
'stage_id': {
- 'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'cancel', 'done'],
+ 'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: obj.state not in ['new', 'draft', 'cancel', 'done'],
},
}
@@ -92,18 +92,6 @@ class crm_lead(base_stage, format_address, osv.osv):
context['empty_list_help_document_name'] = _("leads")
return super(crm_lead, self).get_empty_list_help(cr, uid, help, context=context)
- def create(self, cr, uid, vals, context=None):
- if context is None:
- context = {}
- if not vals.get('stage_id'):
- ctx = context.copy()
- if vals.get('section_id'):
- ctx['default_section_id'] = vals['section_id']
- if vals.get('type'):
- ctx['default_type'] = vals['type']
- vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
- return super(crm_lead, self).create(cr, uid, vals, context=context)
-
def _get_default_section_id(self, cr, uid, context=None):
""" Gives default section by checking if present in the context """
return self._resolve_section_id_from_context(cr, uid, context=context) or False
@@ -123,8 +111,7 @@ class crm_lead(base_stage, format_address, osv.osv):
if type(context.get('default_section_id')) in (int, long):
return context.get('default_section_id')
if isinstance(context.get('default_section_id'), basestring):
- section_name = context['default_section_id']
- section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=section_name, context=context)
+ section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=context['default_section_id'], context=context)
if len(section_ids) == 1:
return int(section_ids[0][0])
return None
@@ -274,7 +261,7 @@ class crm_lead(base_stage, format_address, osv.osv):
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
'date_closed': fields.datetime('Closed', readonly=True),
'stage_id': fields.many2one('crm.case.stage', 'Stage', track_visibility='onchange',
- domain="['&', '&', ('fold', '=', False), ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
+ domain="['&', ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
'user_id': fields.many2one('res.users', 'Salesperson', select=True, track_visibility='onchange'),
'referred': fields.char('Referred By', size=64),
'date_open': fields.datetime('Opened', readonly=True),
@@ -323,8 +310,7 @@ class crm_lead(base_stage, format_address, osv.osv):
_defaults = {
'active': 1,
'type': 'lead',
- 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
- 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
+ 'user_id': lambda s, cr, uid, c: uid,
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
@@ -338,36 +324,35 @@ class crm_lead(base_stage, format_address, osv.osv):
def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
if not stage_id:
- return {'value':{}}
+ return {'value': {}}
stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context)
if not stage.on_change:
- return {'value':{}}
- return {'value':{'probability': stage.probability}}
+ return {'value': {}}
+ return {'value': {'probability': stage.probability}}
- def on_change_partner(self, cr, uid, ids, partner_id, context=None):
- result = {}
+ def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
values = {}
if partner_id:
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
values = {
- 'partner_name' : partner.name,
- 'street' : partner.street,
- 'street2' : partner.street2,
- 'city' : partner.city,
- 'state_id' : partner.state_id and partner.state_id.id or False,
- 'country_id' : partner.country_id and partner.country_id.id or False,
- 'email_from' : partner.email,
- 'phone' : partner.phone,
- 'mobile' : partner.mobile,
- 'fax' : partner.fax,
+ 'partner_name': partner.name,
+ 'street': partner.street,
+ 'street2': partner.street2,
+ 'city': partner.city,
+ 'state_id': partner.state_id and partner.state_id.id or False,
+ 'country_id': partner.country_id and partner.country_id.id or False,
+ 'email_from': partner.email,
+ 'phone': partner.phone,
+ 'mobile': partner.mobile,
+ 'fax': partner.fax,
}
- return {'value' : values}
+ return {'value': values}
def on_change_user(self, cr, uid, ids, user_id, context=None):
""" When changing the user, also set a section_id or restrict section id
to the ones user_id is member of. """
- section_id = False
- if user_id:
+ section_id = self._get_default_section_id(cr, uid, context=context) or False
+ if user_id and not section_id:
section_ids = self.pool.get('crm.case.section').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
if section_ids:
section_id = section_ids[0]
@@ -402,7 +387,7 @@ class crm_lead(base_stage, format_address, osv.osv):
# collect all section_ids
section_ids = []
types = ['both']
- if not cases :
+ if not cases:
type = context.get('default_type')
types += [type]
if section_id:
@@ -430,24 +415,18 @@ class crm_lead(base_stage, format_address, osv.osv):
return stage_ids[0]
return False
- def case_cancel(self, cr, uid, ids, context=None):
- """ Overrides case_cancel from base_stage to set probability """
- res = super(crm_lead, self).case_cancel(cr, uid, ids, context=context)
- self.write(cr, uid, ids, {'probability' : 0.0}, context=context)
- return res
-
- def case_reset(self, cr, uid, ids, context=None):
- """ Overrides case_reset from base_stage to set probability """
- res = super(crm_lead, self).case_reset(cr, uid, ids, context=context)
- self.write(cr, uid, ids, {'probability': 0.0}, context=context)
- return res
+ def stage_set(self, cr, uid, ids, stage_id, context=None):
+ """ Set the new stage. Now just writes the stage.
+ TDE TODO: remove me when removing state
+ """
+ return self.write(cr, uid, ids, {'stage_id': stage_id}, context=context)
def case_mark_lost(self, cr, uid, ids, context=None):
""" Mark the case as lost: state=cancel and probability=0 """
for lead in self.browse(cr, uid, ids):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0),('on_change','=',True)], context=context)
if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0}, new_stage_id=stage_id, context=context)
+ self.stage_set(cr, uid, [lead.id], stage_id, context=context)
return True
def case_mark_won(self, cr, uid, ids, context=None):
@@ -455,7 +434,21 @@ class crm_lead(base_stage, format_address, osv.osv):
for lead in self.browse(cr, uid, ids):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0),('on_change','=',True)], context=context)
if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0}, new_stage_id=stage_id, context=context)
+ self.stage_set(cr, uid, [lead.id], stage_id, context=context)
+ return True
+
+ def case_escalate(self, cr, uid, ids, context=None):
+ """ Escalates case to parent level """
+ for case in self.browse(cr, uid, ids, context=context):
+ data = {'active': True}
+ if case.section_id.parent_id:
+ data['section_id'] = case.section_id.parent_id.id
+ if case.section_id.parent_id.change_responsible:
+ if case.section_id.parent_id.user_id:
+ data['user_id'] = case.section_id.parent_id.user_id.id
+ else:
+ raise osv.except_osv(_('Error!'), _("You are already at the top level of your sales-team category.\nTherefore you cannot escalate furthermore."))
+ self.write(cr, uid, [case.id], data, context=context)
return True
def set_priority(self, cr, uid, ids, priority):
@@ -677,8 +670,9 @@ class crm_lead(base_stage, format_address, osv.osv):
merged_data['stage_id'] = section_stage_ids and section_stage_ids[0] or False
# Write merged data into first opportunity
self.write(cr, uid, [highest.id], merged_data, context=context)
- # Delete tail opportunities
- self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context)
+ # Delete tail opportunities
+ # We use the SUPERUSER to avoid access rights issues because as the user had the rights to see the records it should be safe to do so
+ self.unlink(cr, SUPERUSER_ID, [x.id for x in tail_opportunities], context=context)
return highest.id
@@ -715,7 +709,6 @@ class crm_lead(base_stage, format_address, osv.osv):
continue
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
self.write(cr, uid, [lead.id], vals, context=context)
- self.message_post(cr, uid, ids, body=_("Lead converted into an Opportunity"), subtype="crm.mt_lead_convert_to_opportunity", context=context)
if user_ids or section_id:
self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)
@@ -929,12 +922,22 @@ class crm_lead(base_stage, format_address, osv.osv):
}
return res
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if vals.get('type') and not context.get('default_type'):
+ context['default_type'] = vals.get('type')
+ if vals.get('section_id') and not context.get('default_section_id'):
+ context['default_section_id'] = vals.get('section_id')
+
+ # context: no_log, because subtype already handle this
+ create_context = dict(context, mail_create_nolog=True)
+ return super(crm_lead, self).create(cr, uid, vals, context=create_context)
+
def write(self, cr, uid, ids, vals, context=None):
if vals.get('stage_id') and not vals.get('probability'):
- # change probability of lead(s) if required by stage
- stage = self.pool.get('crm.case.stage').browse(cr, uid, vals['stage_id'], context=context)
- if stage.on_change:
- vals['probability'] = stage.probability
+ onchange_stage_values = self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value']
+ vals.update(onchange_stage_values)
return super(crm_lead, self).write(cr, uid, ids, vals, context=context)
def new_mail_send(self, cr, uid, ids, context=None):
@@ -980,15 +983,28 @@ class crm_lead(base_stage, format_address, osv.osv):
def message_get_reply_to(self, cr, uid, ids, context=None):
""" Override to get the reply_to of the parent project. """
return [lead.section_id.message_get_reply_to()[0] if lead.section_id else False
- for lead in self.browse(cr, uid, ids, context=context)]
+ for lead in self.browse(cr, SUPERUSER_ID, ids, context=context)]
+
+ def _get_formview_action(self, cr, uid, id, context=None):
+ action = super(crm_lead, self)._get_formview_action(cr, uid, id, context=context)
+ obj = self.browse(cr, uid, id, context=context)
+ if obj.type == 'opportunity':
+ model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
+ action.update({
+ 'views': [(view_id, 'form')],
+ })
+ return action
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
recipients = super(crm_lead, self).message_get_suggested_recipients(cr, uid, ids, context=context)
- for lead in self.browse(cr, uid, ids, context=context):
- if lead.partner_id:
- self._message_add_suggested_recipient(cr, uid, recipients, lead, partner=lead.partner_id, reason=_('Customer'))
- elif lead.email_from:
- self._message_add_suggested_recipient(cr, uid, recipients, lead, email=lead.email_from, reason=_('Customer Email'))
+ try:
+ for lead in self.browse(cr, uid, ids, context=context):
+ if lead.partner_id:
+ self._message_add_suggested_recipient(cr, uid, recipients, lead, partner=lead.partner_id, reason=_('Customer'))
+ elif lead.email_from:
+ self._message_add_suggested_recipient(cr, uid, recipients, lead, email=lead.email_from, reason=_('Customer Email'))
+ except (osv.except_osv, orm.except_orm): # no read access rights -> just ignore suggested recipients because this imply modifying followers
+ pass
return recipients
def message_new(self, cr, uid, msg, custom_values=None, context=None):
@@ -1008,7 +1024,7 @@ class crm_lead(base_stage, format_address, osv.osv):
'user_id': False,
}
if msg.get('author_id'):
- defaults.update(self.on_change_partner(cr, uid, None, msg.get('author_id'), context=context)['value'])
+ defaults.update(self.on_change_partner_id(cr, uid, None, msg.get('author_id'), context=context)['value'])
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
defaults['priority'] = msg.get('priority')
defaults.update(custom_values)
diff --git a/addons/crm/crm_lead_data.xml b/addons/crm/crm_lead_data.xml
index 0979a94eb3f..92914542d9d 100644
--- a/addons/crm/crm_lead_data.xml
+++ b/addons/crm/crm_lead_data.xml
@@ -163,12 +163,6 @@
Opportunity created
-
- Lead to Opportunity
- crm.lead
-
- Lead converted into an opportunity
- Stage Changedcrm.lead
@@ -195,13 +189,6 @@
section_id
-
- Lead to Opportunity
-
- crm.case.section
-
- section_id
- Opportunity Stage Changedcrm.case.section
diff --git a/addons/crm/crm_lead_demo.xml b/addons/crm/crm_lead_demo.xml
index 21d60ad2961..3917fadbd32 100644
--- a/addons/crm/crm_lead_demo.xml
+++ b/addons/crm/crm_lead_demo.xml
@@ -20,7 +20,7 @@
1
-
+ Hello,
@@ -44,7 +44,7 @@ Can you send me the details ?4
-
+
@@ -63,7 +63,7 @@ Can you send me the details ?
2
-
+
@@ -82,7 +82,7 @@ Can you send me the details ?
3
-
+
@@ -133,7 +133,7 @@ Contact: +1 813 494 5005
3
-
+
@@ -152,7 +152,7 @@ Contact: +1 813 494 5005
5
-
+
@@ -197,6 +197,9 @@ Contact: +1 813 494 5005
+
+
+ lead
@@ -211,7 +214,7 @@ Contact: +1 813 494 5005
2
-
+ Hi,
@@ -235,7 +238,7 @@ Andrew3
-
+
@@ -260,13 +263,6 @@ Andrew
-
-
-
Meeting for pricing information.
-
+
@@ -317,7 +313,7 @@ Andrew
Send Catalogue by Email
-
+
@@ -326,7 +322,7 @@ Andrew
opportunityPlan to buy RedHat servers
-
+ 69 rue de Chimay
@@ -339,10 +335,11 @@ Andrew
Call to ask system requirement
-
+
-
+
+
@@ -367,6 +364,7 @@ Andrew
+
@@ -388,10 +386,11 @@ Andrew
Send price list regarding our interventions
-
+
-
+
+
@@ -412,7 +411,7 @@ Andrew
Call to define real needs about training
-
+
@@ -438,8 +437,9 @@ Andrew
Ask for the good receprion of the proposition
-
+
+
@@ -468,10 +468,11 @@ Andrew
3
-
+
-
+
+
@@ -486,7 +487,7 @@ Andrew
3
-
+
@@ -504,14 +505,15 @@ Andrew
5
-
+
+ opportunityNeed 20 Days of Consultancy
-
+ info@mycompany.net
@@ -525,6 +527,7 @@ Andrew
+
@@ -544,7 +547,7 @@ Andrew
2Conf call with technical service
-
+
@@ -569,10 +572,11 @@ Andrew
Send Catalogue by Email
-
+
-
+
+
@@ -698,5 +702,6 @@ Andrew
eval="[ ref('msg_case18_1'), ref('msg_case18_2')], True, {}"
/>
+
diff --git a/addons/crm/crm_lead_menu.xml b/addons/crm/crm_lead_menu.xml
index 2226b4ac895..7ee3287fd75 100644
--- a/addons/crm/crm_lead_menu.xml
+++ b/addons/crm/crm_lead_menu.xml
@@ -12,6 +12,7 @@
{
'default_type':'lead',
'stage_type':'lead',
+ 'needaction_menu_ref': 'crm.menu_crm_opportunities',
'search_default_unassigned':1,
}
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 8c22a0a2e1c..cb4302166a1 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -95,10 +95,6 @@
-
-
@@ -118,7 +114,7 @@
@@ -157,7 +153,8 @@
-
@@ -343,7 +340,7 @@
help="Leads that are assigned to me"/>
+ help="Leads that are assigned to any sales teams I am member of" groups="base.group_multi_salesteams"/>
-
+
@@ -362,7 +359,7 @@
-
+
@@ -556,7 +553,7 @@
-
-
+
@@ -600,7 +597,9 @@
'default_email_to':'{$object.email or \'\'}',
'default_use_template': True,
'default_template_id': ref('crm.email_template_opportunity_mail'),
- }"/>
+ }"
+ groups="base.group_sale_salesman"
+ />
@@ -608,5 +607,23 @@
+
+ Mark As Lost
+
+ code
+
+ if context.get('active_model') == 'crm.lead' and context.get('active_ids'):
+ self.case_mark_lost(cr, uid, context['active_ids'], context=context)
+
+
+
+
+
+
+
+ Mark As Lost
+
+
+
diff --git a/addons/crm/crm_phonecall_demo.xml b/addons/crm/crm_phonecall_demo.xml
index f441c29a7e6..4002e18815e 100644
--- a/addons/crm/crm_phonecall_demo.xml
+++ b/addons/crm/crm_phonecall_demo.xml
@@ -37,7 +37,7 @@
Ask for convenient time of meetingopen+1 786 525 0724
-
+
@@ -50,7 +50,7 @@
done(077) 582-4035(077) 341-3591
-
+
@@ -74,7 +74,7 @@
Proposal for discount offeropen+34 230 953 485
-
+
diff --git a/addons/crm/crm_phonecall_menu.xml b/addons/crm/crm_phonecall_menu.xml
index 2344604a294..f6f94547173 100644
--- a/addons/crm/crm_phonecall_menu.xml
+++ b/addons/crm/crm_phonecall_menu.xml
@@ -58,7 +58,7 @@
tree,calendar[]
- {}
+ {'default_state': 'done'}
diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml
index 63385fa3e17..a84ae553b4a 100644
--- a/addons/crm/crm_view.xml
+++ b/addons/crm/crm_view.xml
@@ -101,7 +101,7 @@
-
+
diff --git a/addons/crm/doc/changelog.rst b/addons/crm/doc/changelog.rst
new file mode 100644
index 00000000000..cb1602a8d39
--- /dev/null
+++ b/addons/crm/doc/changelog.rst
@@ -0,0 +1,11 @@
+.. _changelog:
+
+Changelog
+=========
+
+`trunk (saas-2)`
+----------------
+
+- ``crm``, ``crm_claim``: removed inheritance from ``base_stage`` class. Missing
+ methods have been added into ``crm`` and ``crm_claim``. Also removed inheritance
+ in ``crm_helpdesk`` because it uses states, not stages.
\ No newline at end of file
diff --git a/addons/crm/doc/index.rst b/addons/crm/doc/index.rst
new file mode 100644
index 00000000000..d70e045befe
--- /dev/null
+++ b/addons/crm/doc/index.rst
@@ -0,0 +1,13 @@
+CRM module documentation
+========================
+
+CRM documentation topics
+'''''''''''''''''''''''''
+
+Changelog
+'''''''''
+
+.. toctree::
+ :maxdepth: 1
+
+ changelog.rst
diff --git a/addons/crm/i18n/hu.po b/addons/crm/i18n/hu.po
index 98313efb4f3..0289fac77cf 100644
--- a/addons/crm/i18n/hu.po
+++ b/addons/crm/i18n/hu.po
@@ -7,14 +7,19 @@ 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-04-13 08:42+0000\n"
+"PO-Revision-Date: 2013-07-09 07:36+0000\n"
"Last-Translator: krnkris \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-04-14 05:12+0000\n"
-"X-Generator: Launchpad (build 16564)\n"
+"X-Launchpad-Export-Date: 2013-07-10 05:25+0000\n"
+"X-Generator: Launchpad (build 16696)\n"
+
+#. module: crm
+#: model:crm.case.stage,name:crm.stage_lead3
+msgid "Qualification"
+msgstr "Besorolás"
#. module: crm
#: view:crm.lead.report:0
@@ -31,7 +36,7 @@ msgstr ""
"létrehozását a bejövő levelekből."
#. module: crm
-#: code:addons/crm/crm_lead.py:881
+#: code:addons/crm/crm_lead.py:898
#: selection:crm.case.stage,type:0
#: view:crm.lead:0
#: selection:crm.lead,type:0
@@ -192,8 +197,8 @@ msgstr ""
"direkt HTML formátumú ahhoz hogy beilleszthető legyen a kanban nézetekbe."
#. module: crm
-#: code:addons/crm/crm_lead.py:624
-#: code:addons/crm/crm_lead.py:744
+#: code:addons/crm/crm_lead.py:640
+#: code:addons/crm/crm_lead.py:761
#: code:addons/crm/crm_phonecall.py:280
#, python-format
msgid "Warning!"
@@ -304,7 +309,7 @@ msgid "Prospect Partner"
msgstr "Leendő partner"
#. module: crm
-#: code:addons/crm/crm_lead.py:982
+#: code:addons/crm/crm_lead.py:1002
#, python-format
msgid "No Subject"
msgstr "Nincs tárgy"
@@ -482,7 +487,7 @@ msgid "#Opportunities"
msgstr "Lehetőségek száma"
#. module: crm
-#: code:addons/crm/crm_lead.py:624
+#: code:addons/crm/crm_lead.py:640
#, python-format
msgid ""
"Please select more than one element (lead or opportunity) from the list view."
@@ -782,7 +787,7 @@ msgid "Statistics Dashboard"
msgstr "Statisztika vezérlőpult"
#. module: crm
-#: code:addons/crm/crm_lead.py:861
+#: code:addons/crm/crm_lead.py:878
#: model:crm.case.stage,name:crm.stage_lead2
#: selection:crm.case.stage,type:0
#: view:crm.lead:0
@@ -844,7 +849,7 @@ msgid "Exclusive"
msgstr "Kizárólagos"
#. module: crm
-#: code:addons/crm/crm_lead.py:584
+#: code:addons/crm/crm_lead.py:600
#, python-format
msgid "From %s : %s"
msgstr "Ettől %s : %s"
@@ -1016,7 +1021,7 @@ msgid "Next Action"
msgstr "Következő művelet"
#. module: crm
-#: code:addons/crm/crm_lead.py:763
+#: code:addons/crm/crm_lead.py:780
#, python-format
msgid "Partner set to %s."
msgstr "Partner beállítva mint %s."
@@ -1109,7 +1114,7 @@ msgid "Creation Date"
msgstr "Létrehozás dátuma"
#. module: crm
-#: code:addons/crm/crm_lead.py:698
+#: code:addons/crm/crm_lead.py:715
#, python-format
msgid "Lead converted into an Opportunity"
msgstr "Tervezet lehetőséggé átalakítva lehetőséggé"
@@ -1324,7 +1329,9 @@ msgid "Days to Close"
msgstr "Lezárásig hátralévő napok"
#. module: crm
+#: code:addons/crm/crm_lead.py:1057
#: field:crm.case.section,complete_name:0
+#, python-format
msgid "unknown"
msgstr "Ismeretlen"
@@ -1415,7 +1422,7 @@ msgid "Lead Description"
msgstr "Érdeklődés leírása"
#. module: crm
-#: code:addons/crm/crm_lead.py:565
+#: code:addons/crm/crm_lead.py:581
#, python-format
msgid "Merged opportunities"
msgstr "Lehetőségek összefésülése"
@@ -1989,7 +1996,7 @@ msgid "Leads"
msgstr "Érdeklődők"
#. module: crm
-#: code:addons/crm/crm_lead.py:563
+#: code:addons/crm/crm_lead.py:579
#, python-format
msgid "Merged leads"
msgstr "Össztefésült érdeklődések"
@@ -2085,7 +2092,6 @@ msgid "Global CC"
msgstr "Globális CC /másolat/"
#. module: crm
-#: view:crm.lead:0
#: view:crm.phonecall:0
#: model:ir.actions.act_window,name:crm.crm_case_categ_phone0
#: model:ir.ui.menu,name:crm.menu_crm_case_phone
@@ -2399,7 +2405,7 @@ msgstr "Érdeklődés átalakítva egy lehetőséggé"
#. module: crm
#: view:crm.lead:0
msgid "Unassigned Leads"
-msgstr "Nem iktatott rdeklődések"
+msgstr "Nem iktatott érdeklődések"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_won
@@ -2685,11 +2691,6 @@ msgstr "Valószínűség automatikus változtatása"
msgid "My Phone Calls"
msgstr "Telefonhívásaim"
-#. module: crm
-#: model:crm.case.stage,name:crm.stage_lead3
-msgid "Qualification"
-msgstr "Besorolás"
-
#. module: crm
#: field:crm.lead2opportunity.partner,name:0
#: field:crm.lead2opportunity.partner.mass,name:0
@@ -3100,7 +3101,7 @@ msgid "Working Hours"
msgstr "Munkaórák"
#. module: crm
-#: code:addons/crm/crm_lead.py:968
+#: code:addons/crm/crm_lead.py:986
#: view:crm.lead:0
#: field:crm.lead2opportunity.partner,partner_id:0
#: field:crm.lead2opportunity.partner.mass,partner_id:0
@@ -3960,9 +3961,19 @@ msgstr ""
#~ msgid "Can not add note!"
#~ msgstr "Nem lehet hozzáadni megjegyzést!"
+#, python-format
+#~ msgid ""
+#~ "Opportunity must have Partner assigned before merging with other Opportunity."
+#~ msgstr ""
+#~ "Csak a Partnerhez rendelt Lehetőséget lehet más Lehetőséggel összefűzni."
+
#~ msgid "_Merge"
#~ msgstr "Össze_fésülés"
+#, python-format
+#~ msgid "The opportunity '%s' has been marked as lost."
+#~ msgstr "A '%s' lehetőséget elvesztettnek jelöltem."
+
#, python-format
#~ msgid "Lead '%s' has been converted to an opportunity."
#~ msgstr "A '%s'"
@@ -3990,3 +4001,17 @@ msgstr ""
#~ msgid "Convert To Opportunity"
#~ msgstr "Átalakítás lehetőséggé"
+
+#~ msgid "Edit all Occurrences of recurrent Meeting."
+#~ msgstr "Az ismétlődő találkozók összes eseményének szerkesztése."
+
+#~ msgid ""
+#~ "Leads Analysis allows you to check different CRM related information. Check "
+#~ "for treatment delays, number of responses given and emails sent. You can "
+#~ "sort out your leads analysis by different groups to get accurate grained "
+#~ "analysis."
+#~ msgstr ""
+#~ "Az érdeklődések elemzése több CRM-hez kapcsolódó információt nyújt. "
+#~ "Ellenőrizhetjük az eljárás elnapolását, a kiküldött válaszok és e-mailek "
+#~ "számát. A részletes eredmény érdekében az érdeklődéseket különféle "
+#~ "csoportosítások szerint is elemezhetjük."
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/i18n/ru.po b/addons/crm/i18n/ru.po
index 19ae76e9f46..0029293866c 100644
--- a/addons/crm/i18n/ru.po
+++ b/addons/crm/i18n/ru.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-03-01 11:27+0000\n"
-"Last-Translator: Антон Лаврёнов \n"
+"PO-Revision-Date: 2013-06-06 09:56+0000\n"
+"Last-Translator: Chertykov Denis \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:09+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-07 05:48+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
#. module: crm
#: view:crm.lead.report:0
@@ -56,6 +56,11 @@ msgid ""
"Description: [[object.description]]\n"
" "
msgstr ""
+"Внимание, необработанный кандидат создан более 5 дней назад.\n"
+"Название: [[object.name ]]\n"
+"Идентификатор: [[object.id ]]\n"
+"Описание: [[object.description]]\n"
+" "
#. module: crm
#: field:crm.opportunity2phonecall,action:0
@@ -452,7 +457,7 @@ msgstr "# Предложений"
#, python-format
msgid ""
"Please select more than one element (lead or opportunity) from the list view."
-msgstr ""
+msgstr "Пожалуйста, выберите хотя бы один элемент из списка ниже."
#. module: crm
#: view:crm.lead:0
@@ -953,7 +958,7 @@ msgstr "Следующее действие"
#: code:addons/crm/crm_lead.py:763
#, python-format
msgid "Partner set to %s."
-msgstr ""
+msgstr "Партнер установлен как %s."
#. module: crm
#: selection:crm.lead.report,state:0
@@ -1108,7 +1113,7 @@ msgstr "Удалить"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_create
msgid "Opportunity created"
-msgstr ""
+msgstr "Предложение создано"
#. module: crm
#: view:crm.lead:0
@@ -1397,7 +1402,7 @@ msgstr "Сделать"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_lost
msgid "Opportunity lost"
-msgstr ""
+msgstr "Предложение отклонено"
#. module: crm
#: field:crm.lead2opportunity.partner,action:0
@@ -1446,7 +1451,7 @@ msgstr "Пользователи"
#. module: crm
#: model:mail.message.subtype,name:crm.mt_lead_stage
msgid "Stage Changed"
-msgstr ""
+msgstr "Стадия изменена"
#. module: crm
#: field:crm.case.stage,section_ids:0
@@ -1759,7 +1764,7 @@ msgstr "Способ оплаты"
#. module: crm
#: model:ir.model,name:crm.model_crm_lead2opportunity_partner_mass
msgid "Mass Lead To Opportunity Partner"
-msgstr "Массовое проведение предложений партнёру"
+msgstr "Массовое преобразование кандидатов в предложения"
#. module: crm
#: view:sale.config.settings:0
@@ -1894,7 +1899,7 @@ msgstr "Кандидаты"
#: code:addons/crm/crm_lead.py:563
#, python-format
msgid "Merged leads"
-msgstr ""
+msgstr "Объединенные кандидаты"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor5
@@ -1917,7 +1922,7 @@ msgstr "Сделать"
#: model:mail.message.subtype,name:crm.mt_lead_convert_to_opportunity
#: model:mail.message.subtype,name:crm.mt_salesteam_lead_opportunity
msgid "Lead to Opportunity"
-msgstr ""
+msgstr "Кандидат в предложение"
#. module: crm
#: field:crm.lead,user_email:0
@@ -2126,7 +2131,7 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "Address"
-msgstr ""
+msgstr "Адрес"
#. module: crm
#: help:crm.case.section,alias_id:0
@@ -2134,6 +2139,8 @@ msgid ""
"The email address associated with this team. New emails received will "
"automatically create new leads assigned to the team."
msgstr ""
+"Адрес эл. почты связанный с этой командой. Новая полученная эл. почта будет "
+"автоматически создавать новые кандидаты связанные с командой."
#. module: crm
#: view:crm.lead:0
@@ -2192,7 +2199,7 @@ msgstr "Продолжение процесса"
#: selection:crm.lead2opportunity.partner.mass,name:0
#: model:ir.actions.act_window,name:crm.action_crm_lead2opportunity_partner
msgid "Convert to opportunity"
-msgstr "Преобразовать в возможность"
+msgstr "Преобразовать в предложение"
#. module: crm
#: field:crm.opportunity2phonecall,user_id:0
@@ -2234,6 +2241,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 ""
+"Эта стадия не видима, например в статус-баре или виде канбан, когда нет "
+"записей этой стадии для отображения."
#. module: crm
#: field:crm.lead.report,nbr:0
@@ -2249,7 +2258,7 @@ msgstr "Отдел продаж, которому принадлежит воп
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead6
msgid "Banner Ads"
-msgstr ""
+msgstr "Баннер"
#. module: crm
#: field:crm.merge.opportunity,opportunity_ids:0
@@ -2279,7 +2288,7 @@ msgstr "Выполняется"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_convert_to_opportunity
msgid "Lead converted into an opportunity"
-msgstr ""
+msgstr "Кандидат превращенный в предложение"
#. module: crm
#: view:crm.lead:0
@@ -2289,7 +2298,7 @@ msgstr "Нераспределенные кандидаты"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_won
msgid "Opportunity won"
-msgstr ""
+msgstr "Предложение принято"
#. module: crm
#: field:crm.case.categ,object_id:0
@@ -2364,7 +2373,7 @@ msgstr ""
#. module: crm
#: field:crm.case.stage,state:0
msgid "Related Status"
-msgstr ""
+msgstr "Связанный статус"
#. module: crm
#: field:crm.phonecall,name:0
@@ -2410,7 +2419,7 @@ msgstr "Подтвердить"
#. module: crm
#: view:crm.lead:0
msgid "Unread messages"
-msgstr ""
+msgstr "Непрочитанные сообщения"
#. module: crm
#: field:crm.phonecall.report,section_id:0
@@ -2501,7 +2510,7 @@ msgstr "Создание предложений из кандидатов"
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead3
msgid "Email Campaign - Products"
-msgstr ""
+msgstr "Кампания эл. почты - Продукция"
#. module: crm
#: model:ir.actions.act_window,help:crm.crm_case_categ_phone_incoming0
@@ -2578,7 +2587,7 @@ msgstr "Август"
#: model:mail.message.subtype,name:crm.mt_lead_lost
#: model:mail.message.subtype,name:crm.mt_salesteam_lead_lost
msgid "Opportunity Lost"
-msgstr ""
+msgstr "Предложение отклонено"
#. module: crm
#: field:crm.lead.report,deadline_month:0
@@ -2644,7 +2653,7 @@ msgstr "Сотрудники отдела"
#: view:crm.opportunity2phonecall:0
#: view:crm.phonecall2phonecall:0
msgid "Schedule/Log a Call"
-msgstr ""
+msgstr "Запланировать/Описать звонок"
#. module: crm
#: field:crm.lead,planned_cost:0
@@ -2654,7 +2663,7 @@ msgstr "Планируемые затраты"
#. module: crm
#: help:crm.lead,date_deadline:0
msgid "Estimate of the date on which the opportunity will be won."
-msgstr ""
+msgstr "Оценка даты на которую это предложение будет принято."
#. module: crm
#: help:crm.lead,email_cc:0
@@ -2676,7 +2685,7 @@ msgstr "Описанные звонки"
#: model:mail.message.subtype,name:crm.mt_lead_won
#: model:mail.message.subtype,name:crm.mt_salesteam_lead_won
msgid "Opportunity Won"
-msgstr ""
+msgstr "Предложение принято"
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_case_section_act_tree
@@ -2717,7 +2726,7 @@ msgstr "Улица (2-я строка)"
#. module: crm
#: field:sale.config.settings,module_crm_helpdesk:0
msgid "Manage Helpdesk and Support"
-msgstr ""
+msgstr "Управление поддержкой"
#. module: crm
#: field:crm.lead.report,delay_open:0
@@ -2826,7 +2835,7 @@ msgstr "Дата создания"
#. module: crm
#: view:crm.lead:0
msgid "at"
-msgstr ""
+msgstr "в"
#. module: crm
#: model:crm.case.stage,name:crm.stage_lead1
@@ -2895,7 +2904,7 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "Internal Notes"
-msgstr ""
+msgstr "Внутренние заметки"
#. module: crm
#: view:crm.lead:0
@@ -2960,6 +2969,7 @@ msgstr "Проиграно"
#, python-format
msgid "Closed/Cancelled leads cannot be converted into opportunities."
msgstr ""
+"Закрытые/Отмененные кандидаты не могут быть конвертированы в возможности."
#. module: crm
#: view:crm.lead:0
@@ -3050,7 +3060,7 @@ msgstr "Рассылка"
#. module: crm
#: model:mail.message.subtype,name:crm.mt_salesteam_lead_stage
msgid "Opportunity Stage Changed"
-msgstr ""
+msgstr "Этап предложения изменен"
#. module: crm
#: model:ir.actions.act_window,help:crm.crm_lead_stage_act
diff --git a/addons/crm/process/crm_configuration_process.xml b/addons/crm/process/crm_configuration_process.xml
index c56bb8935d9..882c9680268 100644
--- a/addons/crm/process/crm_configuration_process.xml
+++ b/addons/crm/process/crm_configuration_process.xml
@@ -60,24 +60,24 @@
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/addons/crm/report/crm_lead_report_view.xml b/addons/crm/report/crm_lead_report_view.xml
index 759063b3c1d..09853c6379e 100644
--- a/addons/crm/report/crm_lead_report_view.xml
+++ b/addons/crm/report/crm_lead_report_view.xml
@@ -75,7 +75,7 @@
+ help="Leads/Opportunities that are assigned to one of the sale teams I manage" groups="base.group_multi_salesteams"/>
+ help="Phone calls that are assigned to one of the sale teams I manage" groups="base.group_multi_salesteams"/>
-
+
-
+
diff --git a/addons/crm/res_partner.py b/addons/crm/res_partner.py
index f25b1303c02..fca9222082d 100644
--- a/addons/crm/res_partner.py
+++ b/addons/crm/res_partner.py
@@ -56,7 +56,7 @@ class res_partner(osv.osv):
default.update({'opportunity_ids': [], 'meeting_ids' : [], 'phonecall_ids' : []})
- super(res_partner, self).copy(cr, uid, record_id, default, context)
+ return super(res_partner, self).copy(cr, uid, record_id, default, context)
def redirect_partner_form(self, cr, uid, partner_id, context=None):
search_view = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'view_res_partner_filter')
diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml
index dd6c50dbaba..8b941a395dd 100644
--- a/addons/crm/res_partner_view.xml
+++ b/addons/crm/res_partner_view.xml
@@ -2,19 +2,6 @@
-
-
- view.res.partner.form.crm.inherited1
- res.partner
-
-
-
-
-
-
-
-
-
Meetings
@@ -91,24 +78,31 @@
-
-
- res.partner.view.buttons
+
+
+ view.res.partner.form.crm.inherited1res.partner
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/security/ir.model.access.csv b/addons/crm/security/ir.model.access.csv
index 52648c8e347..cadb8c24550 100644
--- a/addons/crm/security/ir.model.access.csv
+++ b/addons/crm/security/ir.model.access.csv
@@ -12,7 +12,7 @@ access_crm_phonecall_manager,crm.phonecall.manager,model_crm_phonecall,base.grou
access_crm_case_categ,crm.case.categ,model_crm_case_categ,base.group_user,1,0,0,0
access_crm_lead,crm.lead,model_crm_lead,base.group_sale_salesman,1,1,1,0
access_crm_phonecall,crm.phonecall,model_crm_phonecall,base.group_sale_salesman,1,1,1,0
-access_crm_case_section_user,crm.case.section.user,model_crm_case_section,base.group_sale_salesman,1,1,1,0
+access_crm_case_section_user,crm.case.section.user,model_crm_case_section,base.group_sale_salesman,1,0,0,0
access_crm_case_section_manager,crm.case.section.manager,model_crm_case_section,base.group_sale_manager,1,1,1,1
access_crm_case_stage,crm.case.stage,model_crm_case_stage,,1,0,0,0
access_crm_case_stage_manager,crm.case.stage,model_crm_case_stage,base.group_sale_manager,1,1,1,1
@@ -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/static/description/Stephan-Keller.jpg b/addons/crm/static/description/Stephan-Keller.jpg
new file mode 100644
index 00000000000..57464ea0b2b
Binary files /dev/null and b/addons/crm/static/description/Stephan-Keller.jpg differ
diff --git a/addons/crm/static/description/claudia-sebastiani.jpg b/addons/crm/static/description/claudia-sebastiani.jpg
new file mode 100644
index 00000000000..f24ba95189a
Binary files /dev/null and b/addons/crm/static/description/claudia-sebastiani.jpg differ
diff --git a/addons/crm/static/description/crm_game.png b/addons/crm/static/description/crm_game.png
new file mode 100644
index 00000000000..b5416926793
Binary files /dev/null and b/addons/crm/static/description/crm_game.png differ
diff --git a/addons/crm/static/description/crm_game_01.png b/addons/crm/static/description/crm_game_01.png
new file mode 100644
index 00000000000..a3cd109c2de
Binary files /dev/null and b/addons/crm/static/description/crm_game_01.png differ
diff --git a/addons/crm/static/description/crm_game_02.png b/addons/crm/static/description/crm_game_02.png
new file mode 100644
index 00000000000..1a747e1ffe8
Binary files /dev/null and b/addons/crm/static/description/crm_game_02.png differ
diff --git a/addons/crm/static/description/crm_game_03.png b/addons/crm/static/description/crm_game_03.png
new file mode 100644
index 00000000000..2fd14886179
Binary files /dev/null and b/addons/crm/static/description/crm_game_03.png differ
diff --git a/addons/crm/static/description/crm_linkedin.png b/addons/crm/static/description/crm_linkedin.png
new file mode 100644
index 00000000000..e40563dbfc7
Binary files /dev/null and b/addons/crm/static/description/crm_linkedin.png differ
diff --git a/addons/crm/static/description/crm_sc_01.jpg b/addons/crm/static/description/crm_sc_01.jpg
new file mode 100644
index 00000000000..7a2a44d7b0d
Binary files /dev/null and b/addons/crm/static/description/crm_sc_01.jpg differ
diff --git a/addons/crm/static/description/crm_sc_01.png b/addons/crm/static/description/crm_sc_01.png
new file mode 100644
index 00000000000..8f1ff1e95fe
Binary files /dev/null and b/addons/crm/static/description/crm_sc_01.png differ
diff --git a/addons/crm/static/description/crm_sc_02.png b/addons/crm/static/description/crm_sc_02.png
new file mode 100644
index 00000000000..e20c44836ba
Binary files /dev/null and b/addons/crm/static/description/crm_sc_02.png differ
diff --git a/addons/crm/static/description/crm_sc_04a.png b/addons/crm/static/description/crm_sc_04a.png
new file mode 100644
index 00000000000..d0308e3f68b
Binary files /dev/null and b/addons/crm/static/description/crm_sc_04a.png differ
diff --git a/addons/crm/static/description/crm_sc_04b.png b/addons/crm/static/description/crm_sc_04b.png
new file mode 100644
index 00000000000..57b7965771e
Binary files /dev/null and b/addons/crm/static/description/crm_sc_04b.png differ
diff --git a/addons/crm/static/description/crm_sc_04c.png b/addons/crm/static/description/crm_sc_04c.png
new file mode 100644
index 00000000000..d3c4dbae043
Binary files /dev/null and b/addons/crm/static/description/crm_sc_04c.png differ
diff --git a/addons/crm/static/description/crm_sc_04d.png b/addons/crm/static/description/crm_sc_04d.png
new file mode 100644
index 00000000000..687bdfb971f
Binary files /dev/null and b/addons/crm/static/description/crm_sc_04d.png differ
diff --git a/addons/crm/static/description/crm_sc_05.png b/addons/crm/static/description/crm_sc_05.png
new file mode 100644
index 00000000000..b71ce805250
Binary files /dev/null and b/addons/crm/static/description/crm_sc_05.png differ
diff --git a/addons/crm/static/description/crm_sc_06.png b/addons/crm/static/description/crm_sc_06.png
new file mode 100644
index 00000000000..1da7d5e841f
Binary files /dev/null and b/addons/crm/static/description/crm_sc_06.png differ
diff --git a/addons/crm/static/description/crm_sc_08.png b/addons/crm/static/description/crm_sc_08.png
new file mode 100644
index 00000000000..b47d9738cf9
Binary files /dev/null and b/addons/crm/static/description/crm_sc_08.png differ
diff --git a/addons/crm/static/description/crm_sc_agenda.png b/addons/crm/static/description/crm_sc_agenda.png
new file mode 100644
index 00000000000..a0f57eb4bca
Binary files /dev/null and b/addons/crm/static/description/crm_sc_agenda.png differ
diff --git a/addons/crm/static/description/crm_sc_marketing.png b/addons/crm/static/description/crm_sc_marketing.png
new file mode 100644
index 00000000000..f7662587969
Binary files /dev/null and b/addons/crm/static/description/crm_sc_marketing.png differ
diff --git a/addons/crm/static/src/img/icon.png b/addons/crm/static/description/icon.png
similarity index 100%
rename from addons/crm/static/src/img/icon.png
rename to addons/crm/static/description/icon.png
diff --git a/addons/crm/static/description/index.html b/addons/crm/static/description/index.html
new file mode 100644
index 00000000000..70f52d0ca87
--- /dev/null
+++ b/addons/crm/static/description/index.html
@@ -0,0 +1,252 @@
+
+
+Manage your sales funnel with no effort. Attract leads, follow-up on phone calls and meetings. Analyse the quality of your leads to make informed decisions and save time by integrating emails directly into the application.
+
+Track your opportunities pipeline with the revolutionary kanban view. Work inside your sales funnel and get instant visual information about next actions, new messages, top opportunities and expected revenues.
+
+
+
+
+
+
+
+
+
+
+
+
+
Social Network Integration
+
+
+
+
+
+
+
+Bring social intelligence to your sales process. Gain insights from social media site LinkedIn to find prospects easily and load their data automatically into your address book.
+
+
+
+
+
+
+
+
+
Lead Management Made Easy
+
+
+Create leads automatically from incoming emails. Analyse leads efficiency and compare performance by campaigns, channels or sales team.
+
+
+Find duplicates, merge leads and assign them to the right salesperson in one operation. Spend less time on administration and more time on qualifying leads.
+
+
+
+
+
+
+
+
+
+
+
+
+
Organize Your Opportunities
+
A clean user interface with everything in one screen
+
+
+
+
+
+
+
+Get your opportunities organized to stay focused on the best deals. Manage all your customer interactions from the opportunity like emails, phone calls, internal notes, meetings and quotations.
+
+Follow opportunities that interrests you to get notified upon specific events: deal won or lost, stage changed, new customer demand, etc.
+
+
+
+
+
+
+
+
Email Integration and Automation
+
+
+Work with the email applications you already use every day. Whether your company uses Microsoft Outlook or Gmail, no one needs to change the way they work, so everyone stays productive.
+
+Route, sort and filter incoming emails automatically. OpenERP CRM handles incoming emails and route them to the right opportunities or sales team. New leads are created on the fly and interested salespersons are notified automatically.
+
+
+
+
+
+
+
+
+
+
+
+
+
Collaborative Agenda
+
+
+
+
+
+
+
+Schedule your meetings and phone calls using the integrated calendar. You can see your agenda and your colleagues' in one view. As a manager, it's easy to see what your team is busy with.
+
+
+
+
+
+
+
+
Lead Automation and Marketing Campaigns
+
Drive performance by automating tasks
+
+
+ Use our marketing campaigns to automate lead acquisition, follow ups and promotions. Define automated actions (e.g. ask a salesperson to call, send an email, ...) based on triggers (no activity since 20 days, answered a promotional email, etc.)
+
+ Optimize campaigns from lead to close, on every channel. Make smarter decisions about where to invest and show the impact of your marketing activities on your company's bottom line.
+
+
+
+
+
+
+
+
+
+
+
+
+
Customize Your Sales Cycle
+
It Fits Your Sales Approach
+
+Customize your sales cycle by configuring sales stages that perfectly fit your sales approach. Control statistics to get accurate forecasts to improve your sales performance at every stage of your customer relationship.
+
+
+
+
+
+
+
+
+
+
+
+
+
Reporting and Dashboards
+
Get access to the right information to take smart decisions
+
+
+
+
+
+
+
+Get the insights you need to make smarter decisions. Design custom dashboards to get a picture of your business at a glance. Dig deeper with real-time reports that anyone can create and share.
+
+
+
+
+
+
+
+
Drive Engagement with Gamification
+
Leverage sales' natural desire for competition
+
+ Reinforce good habits and improve win rates with real-time recognition and rewards inspired by game mechanics. Align sales teams around clear business objectives with challenges, personal objectives and team leader boards.
+
+
+
Leaderboards
+
+
+
+
+ Promote leaders and competition amongst sales team with performance ratios.
+
+
+
+
Personnal Objectives
+
+
+
+
+ Assign clear goals to users to align them with the company objectives.
+
+
+
+
Team Targets
+
+
+
+
+ Compare revenues with forecasts and budgets in real time.
+
+
+
+
+
+
+
+
+
Many companies already enjoy it
+
Hear what they have to say !
+
+
+
+
+ With OpenERP CRM I keep all the information about leads and customers
+ in a single place, and share it with my colleagues. It's great and effective.
+
+
+
+
+
diff --git a/addons/crm/static/lib/sparkline/jquery.sparkline.js b/addons/crm/static/lib/sparkline/jquery.sparkline.js
new file mode 100644
index 00000000000..c003923e03b
--- /dev/null
+++ b/addons/crm/static/lib/sparkline/jquery.sparkline.js
@@ -0,0 +1,3047 @@
+/**
+*
+* jquery.sparkline.js
+*
+* v2.1.1
+* (c) Splunk, Inc
+* Contact: Gareth Watts (gareth@splunk.com)
+* http://omnipotent.net/jquery.sparkline/
+*
+* Generates inline sparkline charts from data supplied either to the method
+* or inline in HTML
+*
+* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag
+* (Firefox 2.0+, Safari, Opera, etc)
+*
+* License: New BSD License
+*
+* Copyright (c) 2012, Splunk Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+* * Neither the name of Splunk Inc nor the names of its contributors may
+* be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*
+* Usage:
+* $(selector).sparkline(values, options)
+*
+* If values is undefined or set to 'html' then the data values are read from the specified tag:
+*
Sparkline: 1,4,6,6,8,5,3,5
+* $('.sparkline').sparkline();
+* There must be no spaces in the enclosed data set
+*
+* Otherwise values must be an array of numbers or null values
+*
Sparkline: This text replaced if the browser is compatible
+* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])
+* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])
+*
+* Values can also be specified in an HTML comment, or as a values attribute:
+*
Sparkline:
+*
Sparkline:
+* $('.sparkline').sparkline();
+*
+* For line charts, x values can also be specified:
+*
Sparkline: 1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5
+* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
+*
+* By default, options should be passed in as teh second argument to the sparkline function:
+* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
+*
+* Options can also be set by passing them on the tag itself. This feature is disabled by default though
+* as there's a slight performance overhead:
+* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})
+*
Sparkline: loading
+* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionPrefix)
+*
+* Supported options:
+* lineColor - Color of the line used for the chart
+* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart
+* width - Width of the chart - Defaults to 3 times the number of values in pixels
+* height - Height of the chart - Defaults to the height of the containing element
+* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied
+* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied
+* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax
+* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied
+* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied
+* composite - If true then don't erase any existing chart attached to the tag, but draw
+* another chart over the top - Note that width and height are ignored if an
+* existing chart is detected.
+* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'
+* enableTagOptions - Whether to check tags for sparkline options
+* tagOptionPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'
+* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a
+* hidden dom element, avoding a browser reflow
+* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,
+* making the plugin perform much like it did in 1.x
+* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)
+* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled
+* defaults to false (highlights enabled)
+* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase
+* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body
+* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied
+* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis
+* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis
+* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip
+* callback is given arguments of (sparkline, options, fields)
+* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title
+* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)
+* to control the format of the tooltip
+* tooltipPrefix - A string to prepend to each field displayed in a tooltip
+* tooltipSuffix - A string to append to each field displayed in a tooltip
+* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)
+* tooltipValueLookups - An object or range map to map field values to tooltip strings
+* (eg. to map -1 to "Lost", 0 to "Draw", and 1 to "Win")
+* numberFormatter - Optional callback for formatting numbers in tooltips
+* numberDigitGroupSep - Character to use for group separator in numbers "1,234" - Defaults to ","
+* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
+* numberDigitGroupCount - Number of digits between group separator - Defaults to 3
+*
+* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
+* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
+* line - Line chart. Options:
+* spotColor - Set to '' to not end each line in a circular spot
+* minSpotColor - If set, color of spot at minimum value
+* maxSpotColor - If set, color of spot at maximum value
+* spotRadius - Radius in pixels
+* lineWidth - Width of line in pixels
+* normalRangeMin
+* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
+* or expected range of values
+* normalRangeColor - Color to use for the above bar
+* drawNormalOnTop - Draw the normal range above the chart fill color if true
+* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
+* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
+* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
+* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map
+*
+* bar - Bar chart. Options:
+* barColor - Color of bars for postive values
+* negBarColor - Color of bars for negative values
+* zeroColor - Color of bars with zero values
+* nullColor - Color of bars with null values - Defaults to omitting the bar entirely
+* barWidth - Width of bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+* barSpacing - Gap between bars in pixels
+* zeroAxis - Centers the y-axis around zero if true
+*
+* tristate - Charts values of win (>0), lose (<0) or draw (=0)
+* posBarColor - Color of win values
+* negBarColor - Color of lose values
+* zeroBarColor - Color of draw values
+* barWidth - Width of bars in pixels
+* barSpacing - Gap between bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+*
+* discrete - Options:
+* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
+* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
+* thresholdColor
+*
+* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
+* options:
+* targetColor - The color of the vertical target marker
+* targetWidth - The width of the target marker in pixels
+* performanceColor - The color of the performance measure horizontal bar
+* rangeColors - Colors to use for each qualitative range background color
+*
+* pie - Pie chart. Options:
+* sliceColors - An array of colors to use for pie slices
+* offset - Angle in degrees to offset the first slice - Try -90 or +90
+* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
+* borderColor - Color to use for the pie chart border - Defaults to #000
+*
+* box - Box plot. Options:
+* raw - Set to true to supply pre-computed plot points as values
+* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
+* When set to false you can supply any number of values and the box plot will
+* be computed for you. Default is false.
+* showOutliers - Set to true (default) to display outliers as circles
+* outlierIQR - Interquartile range used to determine outliers. Default 1.5
+* boxLineColor - Outline color of the box
+* boxFillColor - Fill color for the box
+* whiskerColor - Line color used for whiskers
+* outlierLineColor - Outline color of outlier circles
+* outlierFillColor - Fill color of the outlier circles
+* spotRadius - Radius of outlier circles
+* medianColor - Line color of the median line
+* target - Draw a target cross hair at the supplied value (default undefined)
+*
+*
+*
+* Examples:
+* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
+* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
+* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
+* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
+* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
+* $('#pie').sparkline([1,1,2], { type:'pie' });
+*/
+
+/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
+
+(function(factory) {
+ if(typeof define === 'function' && define.amd) {
+ define(['jquery'], factory);
+ }
+ else {
+ factory(jQuery);
+ }
+}
+(function($) {
+ 'use strict';
+
+ var UNSET_OPTION = {},
+ getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
+ remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
+ MouseHandler, Tooltip, barHighlightMixin,
+ line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
+ VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
+
+ /**
+ * Default configuration settings
+ */
+ getDefaults = function () {
+ return {
+ // Settings common to most/all chart types
+ common: {
+ type: 'line',
+ lineColor: '#00f',
+ fillColor: '#cdf',
+ defaultPixelsPerValue: 3,
+ width: 'auto',
+ height: 'auto',
+ composite: false,
+ tagValuesAttribute: 'values',
+ tagOptionsPrefix: 'spark',
+ enableTagOptions: false,
+ enableHighlight: true,
+ highlightLighten: 1.4,
+ tooltipSkipNull: true,
+ tooltipPrefix: '',
+ tooltipSuffix: '',
+ disableHiddenCheck: false,
+ numberFormatter: false,
+ numberDigitGroupCount: 3,
+ numberDigitGroupSep: ',',
+ numberDecimalMark: '.',
+ disableTooltips: false,
+ disableInteraction: false
+ },
+ // Defaults for line charts
+ line: {
+ spotColor: '#f80',
+ highlightSpotColor: '#5f5',
+ highlightLineColor: '#f22',
+ spotRadius: 1.5,
+ minSpotColor: '#f80',
+ maxSpotColor: '#f80',
+ lineWidth: 1,
+ normalRangeMin: undefined,
+ normalRangeMax: undefined,
+ normalRangeColor: '#ccc',
+ drawNormalOnTop: false,
+ chartRangeMin: undefined,
+ chartRangeMax: undefined,
+ chartRangeMinX: undefined,
+ chartRangeMaxX: undefined,
+ tooltipFormat: new SPFormat('● {{prefix}}{{y}}{{suffix}}')
+ },
+ // Defaults for bar charts
+ bar: {
+ barColor: '#3366cc',
+ negBarColor: '#f44',
+ stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ zeroColor: undefined,
+ nullColor: undefined,
+ zeroAxis: true,
+ barWidth: 4,
+ barSpacing: 1,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ colorMap: undefined,
+ tooltipFormat: new SPFormat('● {{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for tristate charts
+ tristate: {
+ barWidth: 4,
+ barSpacing: 1,
+ posBarColor: '#6f6',
+ negBarColor: '#f44',
+ zeroBarColor: '#999',
+ colorMap: {},
+ tooltipFormat: new SPFormat('● {{value:map}}'),
+ tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
+ },
+ // Defaults for discrete charts
+ discrete: {
+ lineHeight: 'auto',
+ thresholdColor: undefined,
+ thresholdValue: 0,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for bullet charts
+ bullet: {
+ targetColor: '#f33',
+ targetWidth: 3, // width of the target bar in pixels
+ performanceColor: '#33f',
+ rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
+ base: undefined, // set this to a number to change the base start number
+ tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
+ tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
+ },
+ // Defaults for pie charts
+ pie: {
+ offset: 0,
+ sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ borderWidth: 0,
+ borderColor: '#000',
+ tooltipFormat: new SPFormat('● {{value}} ({{percent.1}}%)')
+ },
+ // Defaults for box plots
+ box: {
+ raw: false,
+ boxLineColor: '#000',
+ boxFillColor: '#cdf',
+ whiskerColor: '#000',
+ outlierLineColor: '#333',
+ outlierFillColor: '#fff',
+ medianColor: '#f00',
+ showOutliers: true,
+ outlierIQR: 1.5,
+ spotRadius: 1.5,
+ target: undefined,
+ targetColor: '#4a2',
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
+ tooltipFormatFieldlistKey: 'field',
+ tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
+ uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
+ lw: 'Left Whisker', rw: 'Right Whisker'} }
+ }
+ };
+ };
+
+ // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname
+ defaultStyles = '.jqstooltip { ' +
+ 'position: absolute;' +
+ 'left: 0px;' +
+ 'top: 0px;' +
+ 'visibility: hidden;' +
+ 'background: rgb(0, 0, 0) transparent;' +
+ 'background-color: rgba(0,0,0,0.6);' +
+ 'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +
+ '-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ 'white-space: nowrap;' +
+ 'padding: 5px;' +
+ 'border: 1px solid white;' +
+ 'z-index: 10000;' +
+ '}' +
+ '.jqsfield { ' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ '}';
+
+ /**
+ * Utilities
+ */
+
+ createClass = function (/* [baseclass, [mixin, ...]], definition */) {
+ var Class, args;
+ Class = function () {
+ this.init.apply(this, arguments);
+ };
+ if (arguments.length > 1) {
+ if (arguments[0]) {
+ Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);
+ Class._super = arguments[0].prototype;
+ } else {
+ Class.prototype = arguments[arguments.length - 1];
+ }
+ if (arguments.length > 2) {
+ args = Array.prototype.slice.call(arguments, 1, -1);
+ args.unshift(Class.prototype);
+ $.extend.apply($, args);
+ }
+ } else {
+ Class.prototype = arguments[0];
+ }
+ Class.prototype.cls = Class;
+ return Class;
+ };
+
+ /**
+ * Wraps a format string for tooltips
+ * {{x}}
+ * {{x.2}
+ * {{x:months}}
+ */
+ $.SPFormatClass = SPFormat = createClass({
+ fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
+ precre: /(\w+)\.(\d+)/,
+
+ init: function (format, fclass) {
+ this.format = format;
+ this.fclass = fclass;
+ },
+
+ render: function (fieldset, lookups, options) {
+ var self = this,
+ fields = fieldset,
+ match, token, lookupkey, fieldvalue, prec;
+ return this.format.replace(this.fre, function () {
+ var lookup;
+ token = arguments[1];
+ lookupkey = arguments[3];
+ match = self.precre.exec(token);
+ if (match) {
+ prec = match[2];
+ token = match[1];
+ } else {
+ prec = false;
+ }
+ fieldvalue = fields[token];
+ if (fieldvalue === undefined) {
+ return '';
+ }
+ if (lookupkey && lookups && lookups[lookupkey]) {
+ lookup = lookups[lookupkey];
+ if (lookup.get) { // RangeMap
+ return lookups[lookupkey].get(fieldvalue) || fieldvalue;
+ } else {
+ return lookups[lookupkey][fieldvalue] || fieldvalue;
+ }
+ }
+ if (isNumber(fieldvalue)) {
+ if (options.get('numberFormatter')) {
+ fieldvalue = options.get('numberFormatter')(fieldvalue);
+ } else {
+ fieldvalue = formatNumber(fieldvalue, prec,
+ options.get('numberDigitGroupCount'),
+ options.get('numberDigitGroupSep'),
+ options.get('numberDecimalMark'));
+ }
+ }
+ return fieldvalue;
+ });
+ }
+ });
+
+ // convience method to avoid needing the new operator
+ $.spformat = function(format, fclass) {
+ return new SPFormat(format, fclass);
+ };
+
+ clipval = function (val, min, max) {
+ if (val < min) {
+ return min;
+ }
+ if (val > max) {
+ return max;
+ }
+ return val;
+ };
+
+ quartile = function (values, q) {
+ var vl;
+ if (q === 2) {
+ vl = Math.floor(values.length / 2);
+ return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;
+ } else {
+ if (values.length % 2 ) { // odd
+ vl = (values.length * q + q) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+ } else { //even
+ vl = (values.length * q + 2) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+
+ }
+ }
+ };
+
+ normalizeValue = function (val) {
+ var nf;
+ switch (val) {
+ case 'undefined':
+ val = undefined;
+ break;
+ case 'null':
+ val = null;
+ break;
+ case 'true':
+ val = true;
+ break;
+ case 'false':
+ val = false;
+ break;
+ default:
+ nf = parseFloat(val);
+ if (val == nf) {
+ val = nf;
+ }
+ }
+ return val;
+ };
+
+ normalizeValues = function (vals) {
+ var i, result = [];
+ for (i = vals.length; i--;) {
+ result[i] = normalizeValue(vals[i]);
+ }
+ return result;
+ };
+
+ remove = function (vals, filter) {
+ var i, vl, result = [];
+ for (i = 0, vl = vals.length; i < vl; i++) {
+ if (vals[i] !== filter) {
+ result.push(vals[i]);
+ }
+ }
+ return result;
+ };
+
+ isNumber = function (num) {
+ return !isNaN(parseFloat(num)) && isFinite(num);
+ };
+
+ formatNumber = function (num, prec, groupsize, groupsep, decsep) {
+ var p, i;
+ num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');
+ p = (p = $.inArray('.', num)) < 0 ? num.length : p;
+ if (p < num.length) {
+ num[p] = decsep;
+ }
+ for (i = p - groupsize; i > 0; i -= groupsize) {
+ num.splice(i, 0, groupsep);
+ }
+ return num.join('');
+ };
+
+ // determine if all values of an array match a value
+ // returns true if the array is empty
+ all = function (val, arr, ignoreNull) {
+ var i;
+ for (i = arr.length; i--; ) {
+ if (ignoreNull && arr[i] === null) continue;
+ if (arr[i] !== val) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // sums the numeric values in an array, ignoring other values
+ sum = function (vals) {
+ var total = 0, i;
+ for (i = vals.length; i--;) {
+ total += typeof vals[i] === 'number' ? vals[i] : 0;
+ }
+ return total;
+ };
+
+ ensureArray = function (val) {
+ return $.isArray(val) ? val : [val];
+ };
+
+ // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/
+ addCSS = function(css) {
+ var tag;
+ //if ('\v' == 'v') /* ie only */ {
+ if (document.createStyleSheet) {
+ document.createStyleSheet().cssText = css;
+ } else {
+ tag = document.createElement('style');
+ tag.type = 'text/css';
+ document.getElementsByTagName('head')[0].appendChild(tag);
+ tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;
+ }
+ };
+
+ // Provide a cross-browser interface to a few simple drawing primitives
+ $.fn.simpledraw = function (width, height, useExisting, interact) {
+ var target, mhandler;
+ if (useExisting && (target = this.data('_jqs_vcanvas'))) {
+ return target;
+ }
+ if (width === undefined) {
+ width = $(this).innerWidth();
+ }
+ if (height === undefined) {
+ height = $(this).innerHeight();
+ }
+ if ($.fn.sparkline.hasCanvas) {
+ target = new VCanvas_canvas(width, height, this, interact);
+ } else if ($.fn.sparkline.hasVML) {
+ target = new VCanvas_vml(width, height, this);
+ } else {
+ return false;
+ }
+ mhandler = $(this).data('_jqs_mhandler');
+ if (mhandler) {
+ mhandler.registerCanvas(target);
+ }
+ return target;
+ };
+
+ $.fn.cleardraw = function () {
+ var target = this.data('_jqs_vcanvas');
+ if (target) {
+ target.reset();
+ }
+ };
+
+ $.RangeMapClass = RangeMap = createClass({
+ init: function (map) {
+ var key, range, rangelist = [];
+ for (key in map) {
+ if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {
+ range = key.split(':');
+ range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
+ range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
+ range[2] = map[key];
+ rangelist.push(range);
+ }
+ }
+ this.map = map;
+ this.rangelist = rangelist || false;
+ },
+
+ get: function (value) {
+ var rangelist = this.rangelist,
+ i, range, result;
+ if ((result = this.map[value]) !== undefined) {
+ return result;
+ }
+ if (rangelist) {
+ for (i = rangelist.length; i--;) {
+ range = rangelist[i];
+ if (range[0] <= value && range[1] >= value) {
+ return range[2];
+ }
+ }
+ }
+ return undefined;
+ }
+ });
+
+ // Convenience function
+ $.range_map = function(map) {
+ return new RangeMap(map);
+ };
+
+ MouseHandler = createClass({
+ init: function (el, options) {
+ var $el = $(el);
+ this.$el = $el;
+ this.options = options;
+ this.currentPageX = 0;
+ this.currentPageY = 0;
+ this.el = el;
+ this.splist = [];
+ this.tooltip = null;
+ this.over = false;
+ this.displayTooltips = !options.get('disableTooltips');
+ this.highlightEnabled = !options.get('disableHighlight');
+ },
+
+ registerSparkline: function (sp) {
+ this.splist.push(sp);
+ if (this.over) {
+ this.updateDisplay();
+ }
+ },
+
+ registerCanvas: function (canvas) {
+ var $canvas = $(canvas.canvas);
+ this.canvas = canvas;
+ this.$canvas = $canvas;
+ $canvas.mouseenter($.proxy(this.mouseenter, this));
+ $canvas.mouseleave($.proxy(this.mouseleave, this));
+ $canvas.click($.proxy(this.mouseclick, this));
+ },
+
+ reset: function (removeTooltip) {
+ this.splist = [];
+ if (this.tooltip && removeTooltip) {
+ this.tooltip.remove();
+ this.tooltip = undefined;
+ }
+ },
+
+ mouseclick: function (e) {
+ var clickEvent = $.Event('sparklineClick');
+ clickEvent.originalEvent = e;
+ clickEvent.sparklines = this.splist;
+ this.$el.trigger(clickEvent);
+ },
+
+ mouseenter: function (e) {
+ $(document.body).unbind('mousemove.jqs');
+ $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));
+ this.over = true;
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (!this.tooltip && this.displayTooltips) {
+ this.tooltip = new Tooltip(this.options);
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ mouseleave: function () {
+ $(document.body).unbind('mousemove.jqs');
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ sp, i;
+ this.over = false;
+ this.currentEl = null;
+
+ if (this.tooltip) {
+ this.tooltip.remove();
+ this.tooltip = null;
+ }
+
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ if (sp.clearRegionHighlight()) {
+ needsRefresh = true;
+ }
+ }
+
+ if (needsRefresh) {
+ this.canvas.render();
+ }
+ },
+
+ mousemove: function (e) {
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (this.tooltip) {
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ updateDisplay: function () {
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ offset = this.$canvas.offset(),
+ localX = this.currentPageX - offset.left,
+ localY = this.currentPageY - offset.top,
+ tooltiphtml, sp, i, result, changeEvent;
+ if (!this.over) {
+ return;
+ }
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ result = sp.setRegionHighlight(this.currentEl, localX, localY);
+ if (result) {
+ needsRefresh = true;
+ }
+ }
+ if (needsRefresh) {
+ changeEvent = $.Event('sparklineRegionChange');
+ changeEvent.sparklines = this.splist;
+ this.$el.trigger(changeEvent);
+ if (this.tooltip) {
+ tooltiphtml = '';
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ tooltiphtml += sp.getCurrentRegionTooltip();
+ }
+ this.tooltip.setContent(tooltiphtml);
+ }
+ if (!this.disableHighlight) {
+ this.canvas.render();
+ }
+ }
+ if (result === null) {
+ this.mouseleave();
+ }
+ }
+ });
+
+
+ Tooltip = createClass({
+ sizeStyle: 'position: static !important;' +
+ 'display: block !important;' +
+ 'visibility: hidden !important;' +
+ 'float: left !important;',
+
+ init: function (options) {
+ var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),
+ sizetipStyle = this.sizeStyle,
+ offset;
+ this.container = options.get('tooltipContainer') || document.body;
+ this.tooltipOffsetX = options.get('tooltipOffsetX', 10);
+ this.tooltipOffsetY = options.get('tooltipOffsetY', 12);
+ // remove any previous lingering tooltip
+ $('#jqssizetip').remove();
+ $('#jqstooltip').remove();
+ this.sizetip = $('', {
+ id: 'jqssizetip',
+ style: sizetipStyle,
+ 'class': tooltipClassname
+ });
+ this.tooltip = $('', {
+ id: 'jqstooltip',
+ 'class': tooltipClassname
+ }).appendTo(this.container);
+ // account for the container's location
+ offset = this.tooltip.offset();
+ this.offsetLeft = offset.left;
+ this.offsetTop = offset.top;
+ this.hidden = true;
+ $(window).unbind('resize.jqs scroll.jqs');
+ $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));
+ this.updateWindowDims();
+ },
+
+ updateWindowDims: function () {
+ this.scrollTop = $(window).scrollTop();
+ this.scrollLeft = $(window).scrollLeft();
+ this.scrollRight = this.scrollLeft + $(window).width();
+ this.updatePosition();
+ },
+
+ getSize: function (content) {
+ this.sizetip.html(content).appendTo(this.container);
+ this.width = this.sizetip.width() + 1;
+ this.height = this.sizetip.height();
+ this.sizetip.remove();
+ },
+
+ setContent: function (content) {
+ if (!content) {
+ this.tooltip.css('visibility', 'hidden');
+ this.hidden = true;
+ return;
+ }
+ this.getSize(content);
+ this.tooltip.html(content)
+ .css({
+ 'width': this.width,
+ 'height': this.height,
+ 'visibility': 'visible'
+ });
+ if (this.hidden) {
+ this.hidden = false;
+ this.updatePosition();
+ }
+ },
+
+ updatePosition: function (x, y) {
+ if (x === undefined) {
+ if (this.mousex === undefined) {
+ return;
+ }
+ x = this.mousex - this.offsetLeft;
+ y = this.mousey - this.offsetTop;
+
+ } else {
+ this.mousex = x = x - this.offsetLeft;
+ this.mousey = y = y - this.offsetTop;
+ }
+ if (!this.height || !this.width || this.hidden) {
+ return;
+ }
+
+ y -= this.height + this.tooltipOffsetY;
+ x += this.tooltipOffsetX;
+
+ if (y < this.scrollTop) {
+ y = this.scrollTop;
+ }
+ if (x < this.scrollLeft) {
+ x = this.scrollLeft;
+ } else if (x + this.width > this.scrollRight) {
+ x = this.scrollRight - this.width;
+ }
+
+ this.tooltip.css({
+ 'left': x,
+ 'top': y
+ });
+ },
+
+ remove: function () {
+ this.tooltip.remove();
+ this.sizetip.remove();
+ this.sizetip = this.tooltip = undefined;
+ $(window).unbind('resize.jqs scroll.jqs');
+ }
+ });
+
+ initStyles = function() {
+ addCSS(defaultStyles);
+ };
+
+ $(initStyles);
+
+ pending = [];
+ $.fn.sparkline = function (userValues, userOptions) {
+ return this.each(function () {
+ var options = new $.fn.sparkline.options(this, userOptions),
+ $this = $(this),
+ render, i;
+ render = function () {
+ var values, width, height, tmp, mhandler, sp, vals;
+ if (userValues === 'html' || userValues === undefined) {
+ vals = this.getAttribute(options.get('tagValuesAttribute'));
+ if (vals === undefined || vals === null) {
+ vals = $this.html();
+ }
+ values = vals.replace(/(^\s*\s*$)|\s+/g, '').split(',');
+ } else {
+ values = userValues;
+ }
+
+ width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');
+ if (options.get('height') === 'auto') {
+ if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {
+ // must be a better way to get the line height
+ tmp = document.createElement('span');
+ tmp.innerHTML = 'a';
+ $this.html(tmp);
+ height = $(tmp).innerHeight() || $(tmp).height();
+ $(tmp).remove();
+ tmp = null;
+ }
+ } else {
+ height = options.get('height');
+ }
+
+ if (!options.get('disableInteraction')) {
+ mhandler = $.data(this, '_jqs_mhandler');
+ if (!mhandler) {
+ mhandler = new MouseHandler(this, options);
+ $.data(this, '_jqs_mhandler', mhandler);
+ } else if (!options.get('composite')) {
+ mhandler.reset();
+ }
+ } else {
+ mhandler = false;
+ }
+
+ if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {
+ if (!$.data(this, '_jqs_errnotify')) {
+ alert('Attempted to attach a composite sparkline to an element with no existing sparkline');
+ $.data(this, '_jqs_errnotify', true);
+ }
+ return;
+ }
+
+ sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);
+
+ sp.render();
+
+ if (mhandler) {
+ mhandler.registerSparkline(sp);
+ }
+ };
+ // jQuery 1.3.0 completely changed the meaning of :hidden :-/
+ if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || ($.fn.jquery < '1.3.0' && $(this).parents().is(':hidden')) || !$(this).parents('body').length) {
+ if (!options.get('composite') && $.data(this, '_jqs_pending')) {
+ // remove any existing references to the element
+ for (i = pending.length; i; i--) {
+ if (pending[i - 1][0] == this) {
+ pending.splice(i - 1, 1);
+ }
+ }
+ }
+ pending.push([this, render]);
+ $.data(this, '_jqs_pending', true);
+ } else {
+ render.call(this);
+ }
+ });
+ };
+
+ $.fn.sparkline.defaults = getDefaults();
+
+
+ $.sparkline_display_visible = function () {
+ var el, i, pl;
+ var done = [];
+ for (i = 0, pl = pending.length; i < pl; i++) {
+ el = pending[i][0];
+ if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {
+ pending[i][1].call(el);
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {
+ // element has been inserted and removed from the DOM
+ // If it was not yet inserted into the dom then the .data request
+ // will return true.
+ // removing from the dom causes the data to be removed.
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ }
+ }
+ for (i = done.length; i; i--) {
+ pending.splice(done[i - 1], 1);
+ }
+ };
+
+
+ /**
+ * User option handler
+ */
+ $.fn.sparkline.options = createClass({
+ init: function (tag, userOptions) {
+ var extendedOptions, defaults, base, tagOptionType;
+ this.userOptions = userOptions = userOptions || {};
+ this.tag = tag;
+ this.tagValCache = {};
+ defaults = $.fn.sparkline.defaults;
+ base = defaults.common;
+ this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
+
+ tagOptionType = this.getTagSetting('type');
+ if (tagOptionType === UNSET_OPTION) {
+ extendedOptions = defaults[userOptions.type || base.type];
+ } else {
+ extendedOptions = defaults[tagOptionType];
+ }
+ this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);
+ },
+
+
+ getTagSetting: function (key) {
+ var prefix = this.tagOptionsPrefix,
+ val, i, pairs, keyval;
+ if (prefix === false || prefix === undefined) {
+ return UNSET_OPTION;
+ }
+ if (this.tagValCache.hasOwnProperty(key)) {
+ val = this.tagValCache.key;
+ } else {
+ val = this.tag.getAttribute(prefix + key);
+ if (val === undefined || val === null) {
+ val = UNSET_OPTION;
+ } else if (val.substr(0, 1) === '[') {
+ val = val.substr(1, val.length - 2).split(',');
+ for (i = val.length; i--;) {
+ val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else if (val.substr(0, 1) === '{') {
+ pairs = val.substr(1, val.length - 2).split(',');
+ val = {};
+ for (i = pairs.length; i--;) {
+ keyval = pairs[i].split(':', 2);
+ val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else {
+ val = normalizeValue(val);
+ }
+ this.tagValCache.key = val;
+ }
+ return val;
+ },
+
+ get: function (key, defaultval) {
+ var tagOption = this.getTagSetting(key),
+ result;
+ if (tagOption !== UNSET_OPTION) {
+ return tagOption;
+ }
+ return (result = this.mergedOptions[key]) === undefined ? defaultval : result;
+ }
+ });
+
+
+ $.fn.sparkline._base = createClass({
+ disabled: false,
+
+ init: function (el, values, options, width, height) {
+ this.el = el;
+ this.$el = $(el);
+ this.values = values;
+ this.options = options;
+ this.width = width;
+ this.height = height;
+ this.currentRegion = undefined;
+ },
+
+ /**
+ * Setup the canvas
+ */
+ initTarget: function () {
+ var interactive = !this.options.get('disableInteraction');
+ if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {
+ this.disabled = true;
+ } else {
+ this.canvasWidth = this.target.pixelWidth;
+ this.canvasHeight = this.target.pixelHeight;
+ }
+ },
+
+ /**
+ * Actually render the chart to the canvas
+ */
+ render: function () {
+ if (this.disabled) {
+ this.el.innerHTML = '';
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * Return a region id for a given x/y co-ordinate
+ */
+ getRegion: function (x, y) {
+ },
+
+ /**
+ * Highlight an item based on the moused-over x,y co-ordinate
+ */
+ setRegionHighlight: function (el, x, y) {
+ var currentRegion = this.currentRegion,
+ highlightEnabled = !this.options.get('disableHighlight'),
+ newRegion;
+ if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
+ return null;
+ }
+ newRegion = this.getRegion(el, x, y);
+ if (currentRegion !== newRegion) {
+ if (currentRegion !== undefined && highlightEnabled) {
+ this.removeHighlight();
+ }
+ this.currentRegion = newRegion;
+ if (newRegion !== undefined && highlightEnabled) {
+ this.renderHighlight();
+ }
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Reset any currently highlighted item
+ */
+ clearRegionHighlight: function () {
+ if (this.currentRegion !== undefined) {
+ this.removeHighlight();
+ this.currentRegion = undefined;
+ return true;
+ }
+ return false;
+ },
+
+ renderHighlight: function () {
+ this.changeHighlight(true);
+ },
+
+ removeHighlight: function () {
+ this.changeHighlight(false);
+ },
+
+ changeHighlight: function (highlight) {},
+
+ /**
+ * Fetch the HTML to display as a tooltip
+ */
+ getCurrentRegionTooltip: function () {
+ var options = this.options,
+ header = '',
+ entries = [],
+ fields, formats, formatlen, fclass, text, i,
+ showFields, showFieldsKey, newFields, fv,
+ formatter, format, fieldlen, j;
+ if (this.currentRegion === undefined) {
+ return '';
+ }
+ fields = this.getCurrentRegionFields();
+ formatter = options.get('tooltipFormatter');
+ if (formatter) {
+ return formatter(this, options, fields);
+ }
+ if (options.get('tooltipChartTitle')) {
+ header += '
' + options.get('tooltipChartTitle') + '
\n';
+ }
+ formats = this.options.get('tooltipFormat');
+ if (!formats) {
+ return '';
+ }
+ if (!$.isArray(formats)) {
+ formats = [formats];
+ }
+ if (!$.isArray(fields)) {
+ fields = [fields];
+ }
+ showFields = this.options.get('tooltipFormatFieldlist');
+ showFieldsKey = this.options.get('tooltipFormatFieldlistKey');
+ if (showFields && showFieldsKey) {
+ // user-selected ordering of fields
+ newFields = [];
+ for (i = fields.length; i--;) {
+ fv = fields[i][showFieldsKey];
+ if ((j = $.inArray(fv, showFields)) != -1) {
+ newFields[j] = fields[i];
+ }
+ }
+ fields = newFields;
+ }
+ formatlen = formats.length;
+ fieldlen = fields.length;
+ for (i = 0; i < formatlen; i++) {
+ format = formats[i];
+ if (typeof format === 'string') {
+ format = new SPFormat(format);
+ }
+ fclass = format.fclass || 'jqsfield';
+ for (j = 0; j < fieldlen; j++) {
+ if (!fields[j].isNull || !options.get('tooltipSkipNull')) {
+ $.extend(fields[j], {
+ prefix: options.get('tooltipPrefix'),
+ suffix: options.get('tooltipSuffix')
+ });
+ text = format.render(fields[j], options.get('tooltipValueLookups'), options);
+ entries.push('
' + text + '
');
+ }
+ }
+ }
+ if (entries.length) {
+ return header + entries.join('\n');
+ }
+ return '';
+ },
+
+ getCurrentRegionFields: function () {},
+
+ calcHighlightColor: function (color, options) {
+ var highlightColor = options.get('highlightColor'),
+ lighten = options.get('highlightLighten'),
+ parse, mult, rgbnew, i;
+ if (highlightColor) {
+ return highlightColor;
+ }
+ if (lighten) {
+ // extract RGB values
+ parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
+ if (parse) {
+ rgbnew = [];
+ mult = color.length === 4 ? 16 : 1;
+ for (i = 0; i < 3; i++) {
+ rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
+ }
+ return 'rgb(' + rgbnew.join(',') + ')';
+ }
+
+ }
+ return color;
+ }
+
+ });
+
+ barHighlightMixin = {
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ shapeids = this.regionShapes[currentRegion],
+ newShapes;
+ // will be null if the region value was null
+ if (shapeids) {
+ newShapes = this.renderRegion(currentRegion, highlight);
+ if ($.isArray(newShapes) || $.isArray(shapeids)) {
+ target.replaceWithShapes(shapeids, newShapes);
+ this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {
+ return newShape.id;
+ });
+ } else {
+ target.replaceWithShape(shapeids, newShapes);
+ this.regionShapes[currentRegion] = newShapes.id;
+ }
+ }
+ },
+
+ render: function () {
+ var values = this.values,
+ target = this.target,
+ regionShapes = this.regionShapes,
+ shapes, ids, i, j;
+
+ if (!this.cls._super.render.call(this)) {
+ return;
+ }
+ for (i = values.length; i--;) {
+ shapes = this.renderRegion(i);
+ if (shapes) {
+ if ($.isArray(shapes)) {
+ ids = [];
+ for (j = shapes.length; j--;) {
+ shapes[j].append();
+ ids.push(shapes[j].id);
+ }
+ regionShapes[i] = ids;
+ } else {
+ shapes.append();
+ regionShapes[i] = shapes.id; // store just the shapeid
+ }
+ } else {
+ // null value
+ regionShapes[i] = null;
+ }
+ }
+ target.render();
+ }
+ };
+
+ /**
+ * Line charts
+ */
+ $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
+ type: 'line',
+
+ init: function (el, values, options, width, height) {
+ line._super.init.call(this, el, values, options, width, height);
+ this.vertices = [];
+ this.regionMap = [];
+ this.xvalues = [];
+ this.yvalues = [];
+ this.yminmax = [];
+ this.hightlightSpotId = null;
+ this.lastShapeId = null;
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var i,
+ regionMap = this.regionMap; // maps regions to value positions
+ for (i = regionMap.length; i--;) {
+ if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
+ return regionMap[i][2];
+ }
+ }
+ return undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.yvalues[currentRegion] === null,
+ x: this.xvalues[currentRegion],
+ y: this.yvalues[currentRegion],
+ color: this.options.get('lineColor'),
+ fillColor: this.options.get('fillColor'),
+ offset: currentRegion
+ };
+ },
+
+ renderHighlight: function () {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ vertex = this.vertices[currentRegion],
+ options = this.options,
+ spotRadius = options.get('spotRadius'),
+ highlightSpotColor = options.get('highlightSpotColor'),
+ highlightLineColor = options.get('highlightLineColor'),
+ highlightSpot, highlightLine;
+
+ if (!vertex) {
+ return;
+ }
+ if (spotRadius && highlightSpotColor) {
+ highlightSpot = target.drawCircle(vertex[0], vertex[1],
+ spotRadius, undefined, highlightSpotColor);
+ this.highlightSpotId = highlightSpot.id;
+ target.insertAfterShape(this.lastShapeId, highlightSpot);
+ }
+ if (highlightLineColor) {
+ highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
+ this.canvasTop + this.canvasHeight, highlightLineColor);
+ this.highlightLineId = highlightLine.id;
+ target.insertAfterShape(this.lastShapeId, highlightLine);
+ }
+ },
+
+ removeHighlight: function () {
+ var target = this.target;
+ if (this.highlightSpotId) {
+ target.removeShapeId(this.highlightSpotId);
+ this.highlightSpotId = null;
+ }
+ if (this.highlightLineId) {
+ target.removeShapeId(this.highlightLineId);
+ this.highlightLineId = null;
+ }
+ },
+
+ scanValues: function () {
+ var values = this.values,
+ valcount = values.length,
+ xvalues = this.xvalues,
+ yvalues = this.yvalues,
+ yminmax = this.yminmax,
+ i, val, isStr, isArray, sp;
+ for (i = 0; i < valcount; i++) {
+ val = values[i];
+ isStr = typeof(values[i]) === 'string';
+ isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
+ sp = isStr && values[i].split(':');
+ if (isStr && sp.length === 2) { // x:y
+ xvalues.push(Number(sp[0]));
+ yvalues.push(Number(sp[1]));
+ yminmax.push(Number(sp[1]));
+ } else if (isArray) {
+ xvalues.push(val[0]);
+ yvalues.push(val[1]);
+ yminmax.push(val[1]);
+ } else {
+ xvalues.push(i);
+ if (values[i] === null || values[i] === 'null') {
+ yvalues.push(null);
+ } else {
+ yvalues.push(Number(val));
+ yminmax.push(Number(val));
+ }
+ }
+ }
+ if (this.options.get('xvalues')) {
+ xvalues = this.options.get('xvalues');
+ }
+
+ this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
+ this.miny = this.minyorg = Math.min.apply(Math, yminmax);
+
+ this.maxx = Math.max.apply(Math, xvalues);
+ this.minx = Math.min.apply(Math, xvalues);
+
+ this.xvalues = xvalues;
+ this.yvalues = yvalues;
+ this.yminmax = yminmax;
+
+ },
+
+ processRangeOptions: function () {
+ var options = this.options,
+ normalRangeMin = options.get('normalRangeMin'),
+ normalRangeMax = options.get('normalRangeMax');
+
+ if (normalRangeMin !== undefined) {
+ if (normalRangeMin < this.miny) {
+ this.miny = normalRangeMin;
+ }
+ if (normalRangeMax > this.maxy) {
+ this.maxy = normalRangeMax;
+ }
+ }
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
+ this.miny = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
+ this.maxy = options.get('chartRangeMax');
+ }
+ if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
+ this.minx = options.get('chartRangeMinX');
+ }
+ if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
+ this.maxx = options.get('chartRangeMaxX');
+ }
+
+ },
+
+ drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
+ var normalRangeMin = this.options.get('normalRangeMin'),
+ normalRangeMax = this.options.get('normalRangeMax'),
+ ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
+ height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
+ this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
+ },
+
+ render: function () {
+ var options = this.options,
+ target = this.target,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ vertices = this.vertices,
+ spotRadius = options.get('spotRadius'),
+ regionMap = this.regionMap,
+ rangex, rangey, yvallast,
+ canvasTop, canvasLeft,
+ vertex, path, paths, x, y, xnext, xpos, xposnext,
+ last, next, yvalcount, lineShapes, fillShapes, plen,
+ valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
+
+ if (!line._super.render.call(this)) {
+ return;
+ }
+
+ this.scanValues();
+ this.processRangeOptions();
+
+ xvalues = this.xvalues;
+ yvalues = this.yvalues;
+
+ if (!this.yminmax.length || this.yvalues.length < 2) {
+ // empty or all null valuess
+ return;
+ }
+
+ canvasTop = canvasLeft = 0;
+
+ rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
+ rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
+ yvallast = this.yvalues.length - 1;
+
+ if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
+ spotRadius = 0;
+ }
+ if (spotRadius) {
+ // adjust the canvas size as required so that spots will fit
+ hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');
+ if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ canvasTop += Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled ||
+ ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
+ canvasLeft += Math.ceil(spotRadius);
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('spotColor') ||
+ (options.get('minSpotColor') || options.get('maxSpotColor') &&
+ (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ }
+
+
+ canvasHeight--;
+
+ if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ path = [];
+ paths = [path];
+ last = next = null;
+ yvalcount = yvalues.length;
+ for (i = 0; i < yvalcount; i++) {
+ x = xvalues[i];
+ xnext = xvalues[i + 1];
+ y = yvalues[i];
+ xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
+ xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
+ next = xpos + ((xposnext - xpos) / 2);
+ regionMap[i] = [last || 0, next, i];
+ last = next;
+ if (y === null) {
+ if (i) {
+ if (yvalues[i - 1] !== null) {
+ path = [];
+ paths.push(path);
+ }
+ vertices.push(null);
+ }
+ } else {
+ if (y < this.miny) {
+ y = this.miny;
+ }
+ if (y > this.maxy) {
+ y = this.maxy;
+ }
+ if (!path.length) {
+ // previous value was null
+ path.push([xpos, canvasTop + canvasHeight]);
+ }
+ vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
+ path.push(vertex);
+ vertices.push(vertex);
+ }
+ }
+
+ lineShapes = [];
+ fillShapes = [];
+ plen = paths.length;
+ for (i = 0; i < plen; i++) {
+ path = paths[i];
+ if (path.length) {
+ if (options.get('fillColor')) {
+ path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
+ fillShapes.push(path.slice(0));
+ path.pop();
+ }
+ // if there's only a single point in this path, then we want to display it
+ // as a vertical line which means we keep path[0] as is
+ if (path.length > 2) {
+ // else we want the first value
+ path[0] = [path[0][0], path[1][1]];
+ }
+ lineShapes.push(path);
+ }
+ }
+
+ // draw the fill first, then optionally the normal range, then the line on top of that
+ plen = fillShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(fillShapes[i],
+ options.get('fillColor'), options.get('fillColor')).append();
+ }
+
+ if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ plen = lineShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
+ options.get('lineWidth')).append();
+ }
+
+ if (spotRadius && options.get('valueSpots')) {
+ valueSpots = options.get('valueSpots');
+ if (valueSpots.get === undefined) {
+ valueSpots = new RangeMap(valueSpots);
+ }
+ for (i = 0; i < yvalcount; i++) {
+ color = valueSpots.get(yvalues[i]);
+ if (color) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
+ spotRadius, undefined,
+ color).append();
+ }
+ }
+
+ }
+ if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('spotColor')).append();
+ }
+ if (this.maxy !== this.minyorg) {
+ if (spotRadius && options.get('minSpotColor')) {
+ x = xvalues[$.inArray(this.minyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('minSpotColor')).append();
+ }
+ if (spotRadius && options.get('maxSpotColor')) {
+ x = xvalues[$.inArray(this.maxyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('maxSpotColor')).append();
+ }
+ }
+
+ this.lastShapeId = target.getLastShapeId();
+ this.canvasTop = canvasTop;
+ target.render();
+ }
+ });
+
+ /**
+ * Bar charts
+ */
+ $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'bar',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10),
+ chartRangeMin = options.get('chartRangeMin'),
+ chartRangeMax = options.get('chartRangeMax'),
+ chartRangeClip = options.get('chartRangeClip'),
+ stackMin = Infinity,
+ stackMax = -Infinity,
+ isStackString, groupMin, groupMax, stackRanges,
+ numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,
+ stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
+ bar._super.init.call(this, el, values, options, width, height);
+
+ // scan values to determine whether to stack bars
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ val = values[i];
+ isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;
+ if (isStackString || $.isArray(val)) {
+ stacked = true;
+ if (isStackString) {
+ val = values[i] = normalizeValues(val.split(':'));
+ }
+ val = remove(val, null); // min/max will treat null as zero
+ groupMin = Math.min.apply(Math, val);
+ groupMax = Math.max.apply(Math, val);
+ if (groupMin < stackMin) {
+ stackMin = groupMin;
+ }
+ if (groupMax > stackMax) {
+ stackMax = groupMax;
+ }
+ }
+ }
+
+ this.stacked = stacked;
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ this.initTarget();
+
+ if (chartRangeClip) {
+ clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;
+ clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;
+ }
+
+ numValues = [];
+ stackRanges = stacked ? [] : numValues;
+ var stackTotals = [];
+ var stackRangesNeg = [];
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ if (stacked) {
+ vlist = values[i];
+ values[i] = svals = [];
+ stackTotals[i] = 0;
+ stackRanges[i] = stackRangesNeg[i] = 0;
+ for (j = 0, slen = vlist.length; j < slen; j++) {
+ val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
+ if (val !== null) {
+ if (val > 0) {
+ stackTotals[i] += val;
+ }
+ if (stackMin < 0 && stackMax > 0) {
+ if (val < 0) {
+ stackRangesNeg[i] += Math.abs(val);
+ } else {
+ stackRanges[i] += val;
+ }
+ } else {
+ stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));
+ }
+ numValues.push(val);
+ }
+ }
+ } else {
+ val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
+ val = values[i] = normalizeValue(val);
+ if (val !== null) {
+ numValues.push(val);
+ }
+ }
+ }
+ this.max = max = Math.max.apply(Math, numValues);
+ this.min = min = Math.min.apply(Math, numValues);
+ this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;
+ this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;
+
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {
+ min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {
+ max = options.get('chartRangeMax');
+ }
+
+ this.zeroAxis = zeroAxis = options.get('zeroAxis', true);
+ if (min <= 0 && max >= 0 && zeroAxis) {
+ xaxisOffset = 0;
+ } else if (zeroAxis == false) {
+ xaxisOffset = min;
+ } else if (min > 0) {
+ xaxisOffset = min;
+ } else {
+ xaxisOffset = max;
+ }
+ this.xaxisOffset = xaxisOffset;
+
+ range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;
+
+ // as we plot zero/min values a single pixel line, we add a pixel to all other
+ // values - Reduce the effective canvas size to suit
+ this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;
+
+ if (min < xaxisOffset) {
+ yMaxCalc = (stacked && max >= 0) ? stackMax : max;
+ yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
+ if (yoffset !== Math.ceil(yoffset)) {
+ this.canvasHeightEf -= 2;
+ yoffset = Math.ceil(yoffset);
+ }
+ } else {
+ yoffset = this.canvasHeight;
+ }
+ this.yoffset = yoffset;
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+
+ this.range = range;
+ },
+
+ getRegion: function (el, x, y) {
+ var result = Math.floor(x / this.totalBarWidth);
+ return (result < 0 || result >= this.values.length) ? undefined : result;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion,
+ values = ensureArray(this.values[currentRegion]),
+ result = [],
+ value, i;
+ for (i = values.length; i--;) {
+ value = values[i];
+ result.push({
+ isNull: value === null,
+ value: value,
+ color: this.calcColor(i, value, currentRegion),
+ offset: currentRegion
+ });
+ }
+ return result;
+ },
+
+ calcColor: function (stacknum, value, valuenum) {
+ var colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ options = this.options,
+ color, newColor;
+ if (this.stacked) {
+ color = options.get('stackedBarColor');
+ } else {
+ color = (value < 0) ? options.get('negBarColor') : options.get('barColor');
+ }
+ if (value === 0 && options.get('zeroColor') !== undefined) {
+ color = options.get('zeroColor');
+ }
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ }
+ return $.isArray(color) ? color[stacknum % color.length] : color;
+ },
+
+ /**
+ * Render bar(s) for a region
+ */
+ renderRegion: function (valuenum, highlight) {
+ var vals = this.values[valuenum],
+ options = this.options,
+ xaxisOffset = this.xaxisOffset,
+ result = [],
+ range = this.range,
+ stacked = this.stacked,
+ target = this.target,
+ x = valuenum * this.totalBarWidth,
+ canvasHeightEf = this.canvasHeightEf,
+ yoffset = this.yoffset,
+ y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
+
+ vals = $.isArray(vals) ? vals : [vals];
+ valcount = vals.length;
+ val = vals[0];
+ isNull = all(null, vals);
+ allMin = all(xaxisOffset, vals, true);
+
+ if (isNull) {
+ if (options.get('nullColor')) {
+ color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);
+ y = (yoffset > 0) ? yoffset - 1 : yoffset;
+ return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
+ } else {
+ return undefined;
+ }
+ }
+ yoffsetNeg = yoffset;
+ for (i = 0; i < valcount; i++) {
+ val = vals[i];
+
+ if (stacked && val === xaxisOffset) {
+ if (!allMin || minPlotted) {
+ continue;
+ }
+ minPlotted = true;
+ }
+
+ if (range > 0) {
+ height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;
+ } else {
+ height = 1;
+ }
+ if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {
+ y = yoffsetNeg;
+ yoffsetNeg += height;
+ } else {
+ y = yoffset - height;
+ yoffset -= height;
+ }
+ color = this.calcColor(i, val, valuenum);
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
+ }
+ if (result.length === 1) {
+ return result[0];
+ }
+ return result;
+ }
+ });
+
+ /**
+ * Tristate charts
+ */
+ $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'tristate',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10);
+ tristate._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.values = $.map(values, Number);
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.totalBarWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ color: this.calcColor(this.values[currentRegion], currentRegion),
+ offset: currentRegion
+ };
+ },
+
+ calcColor: function (value, valuenum) {
+ var values = this.values,
+ options = this.options,
+ colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ color, newColor;
+
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ } else if (values[valuenum] < 0) {
+ color = options.get('negBarColor');
+ } else if (values[valuenum] > 0) {
+ color = options.get('posBarColor');
+ } else {
+ color = options.get('zeroBarColor');
+ }
+ return color;
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ target = this.target,
+ canvasHeight, height, halfHeight,
+ x, y, color;
+
+ canvasHeight = target.pixelHeight;
+ halfHeight = Math.round(canvasHeight / 2);
+
+ x = valuenum * this.totalBarWidth;
+ if (values[valuenum] < 0) {
+ y = halfHeight;
+ height = halfHeight - 1;
+ } else if (values[valuenum] > 0) {
+ y = 0;
+ height = halfHeight - 1;
+ } else {
+ y = halfHeight - 1;
+ height = 2;
+ }
+ color = this.calcColor(values[valuenum], valuenum);
+ if (color === null) {
+ return;
+ }
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
+ }
+ });
+
+ /**
+ * Discrete charts
+ */
+ $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'discrete',
+
+ init: function (el, values, options, width, height) {
+ discrete._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.values = values = $.map(values, Number);
+ this.min = Math.min.apply(Math, values);
+ this.max = Math.max.apply(Math, values);
+ this.range = this.max - this.min;
+ this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
+ this.interval = Math.floor(width / values.length);
+ this.itemWidth = width / values.length;
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
+ this.min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
+ this.max = options.get('chartRangeMax');
+ }
+ this.initTarget();
+ if (this.target) {
+ this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
+ }
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.itemWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ offset: currentRegion
+ };
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ min = this.min,
+ max = this.max,
+ range = this.range,
+ interval = this.interval,
+ target = this.target,
+ canvasHeight = this.canvasHeight,
+ lineHeight = this.lineHeight,
+ pheight = canvasHeight - lineHeight,
+ ytop, val, color, x;
+
+ val = clipval(values[valuenum], min, max);
+ x = valuenum * interval;
+ ytop = Math.round(pheight - pheight * ((val - min) / range));
+ color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawLine(x, ytop, x, ytop + lineHeight, color);
+ }
+ });
+
+ /**
+ * Bullet charts
+ */
+ $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
+ type: 'bullet',
+
+ init: function (el, values, options, width, height) {
+ var min, max, vals;
+ bullet._super.init.call(this, el, values, options, width, height);
+
+ // values: target, performance, range1, range2, range3
+ this.values = values = normalizeValues(values);
+ // target or performance could be null
+ vals = values.slice();
+ vals[0] = vals[0] === null ? vals[2] : vals[0];
+ vals[1] = values[1] === null ? vals[2] : vals[1];
+ min = Math.min.apply(Math, values);
+ max = Math.max.apply(Math, values);
+ if (options.get('base') === undefined) {
+ min = min < 0 ? min : 0;
+ } else {
+ min = options.get('base');
+ }
+ this.min = min;
+ this.max = max;
+ this.range = max - min;
+ this.shapes = {};
+ this.valueShapes = {};
+ this.regiondata = {};
+ this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.target = this.$el.simpledraw(width, height, options.get('composite'));
+ if (!values.length) {
+ this.disabled = true;
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ fieldkey: currentRegion.substr(0, 1),
+ value: this.values[currentRegion.substr(1)],
+ region: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ shapeid = this.valueShapes[currentRegion],
+ shape;
+ delete this.shapes[shapeid];
+ switch (currentRegion.substr(0, 1)) {
+ case 'r':
+ shape = this.renderRange(currentRegion.substr(1), highlight);
+ break;
+ case 'p':
+ shape = this.renderPerformance(highlight);
+ break;
+ case 't':
+ shape = this.renderTarget(highlight);
+ break;
+ }
+ this.valueShapes[currentRegion] = shape.id;
+ this.shapes[shape.id] = currentRegion;
+ this.target.replaceWithShape(shapeid, shape);
+ },
+
+ renderRange: function (rn, highlight) {
+ var rangeval = this.values[rn],
+ rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
+ color = this.options.get('rangeColors')[rn - 2];
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
+ },
+
+ renderPerformance: function (highlight) {
+ var perfval = this.values[1],
+ perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
+ color = this.options.get('performanceColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
+ Math.round(this.canvasHeight * 0.4) - 1, color, color);
+ },
+
+ renderTarget: function (highlight) {
+ var targetval = this.values[0],
+ x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
+ targettop = Math.round(this.canvasHeight * 0.10),
+ targetheight = this.canvasHeight - (targettop * 2),
+ color = this.options.get('targetColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
+ },
+
+ render: function () {
+ var vlen = this.values.length,
+ target = this.target,
+ i, shape;
+ if (!bullet._super.render.call(this)) {
+ return;
+ }
+ for (i = 2; i < vlen; i++) {
+ shape = this.renderRange(i).append();
+ this.shapes[shape.id] = 'r' + i;
+ this.valueShapes['r' + i] = shape.id;
+ }
+ if (this.values[1] !== null) {
+ shape = this.renderPerformance().append();
+ this.shapes[shape.id] = 'p1';
+ this.valueShapes.p1 = shape.id;
+ }
+ if (this.values[0] !== null) {
+ shape = this.renderTarget().append();
+ this.shapes[shape.id] = 't0';
+ this.valueShapes.t0 = shape.id;
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Pie charts
+ */
+ $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
+ type: 'pie',
+
+ init: function (el, values, options, width, height) {
+ var total = 0, i;
+
+ pie._super.init.call(this, el, values, options, width, height);
+
+ this.shapes = {}; // map shape ids to value offsets
+ this.valueShapes = {}; // maps value offsets to shape ids
+ this.values = values = $.map(values, Number);
+
+ if (options.get('width') === 'auto') {
+ this.width = this.height;
+ }
+
+ if (values.length > 0) {
+ for (i = values.length; i--;) {
+ total += values[i];
+ }
+ }
+ this.total = total;
+ this.initTarget();
+ this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ percent: this.values[currentRegion] / this.total * 100,
+ color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
+ offset: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ newslice = this.renderSlice(currentRegion, highlight),
+ shapeid = this.valueShapes[currentRegion];
+ delete this.shapes[shapeid];
+ this.target.replaceWithShape(shapeid, newslice);
+ this.valueShapes[currentRegion] = newslice.id;
+ this.shapes[newslice.id] = currentRegion;
+ },
+
+ renderSlice: function (valuenum, highlight) {
+ var target = this.target,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ offset = options.get('offset'),
+ circle = 2 * Math.PI,
+ values = this.values,
+ total = this.total,
+ next = offset ? (2*Math.PI)*(offset/360) : 0,
+ start, end, i, vlen, color;
+
+ vlen = values.length;
+ for (i = 0; i < vlen; i++) {
+ start = next;
+ end = next;
+ if (total > 0) { // avoid divide by zero
+ end = next + (circle * (values[i] / total));
+ }
+ if (valuenum === i) {
+ color = options.get('sliceColors')[i % options.get('sliceColors').length];
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+
+ return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
+ }
+ next = end;
+ }
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ shape, i;
+
+ if (!pie._super.render.call(this)) {
+ return;
+ }
+ if (borderWidth) {
+ target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
+ options.get('borderColor'), undefined, borderWidth).append();
+ }
+ for (i = values.length; i--;) {
+ if (values[i]) { // don't render zero values
+ shape = this.renderSlice(i).append();
+ this.valueShapes[i] = shape.id; // store just the shapeid
+ this.shapes[shape.id] = i;
+ }
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Box plots
+ */
+ $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
+ type: 'box',
+
+ init: function (el, values, options, width, height) {
+ box._super.init.call(this, el, values, options, width, height);
+ this.values = $.map(values, Number);
+ this.width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.initTarget();
+ if (!this.values.length) {
+ this.disabled = 1;
+ }
+ },
+
+ /**
+ * Simulate a single region
+ */
+ getRegion: function () {
+ return 1;
+ },
+
+ getCurrentRegionFields: function () {
+ var result = [
+ { field: 'lq', value: this.quartiles[0] },
+ { field: 'med', value: this.quartiles[1] },
+ { field: 'uq', value: this.quartiles[2] }
+ ];
+ if (this.loutlier !== undefined) {
+ result.push({ field: 'lo', value: this.loutlier});
+ }
+ if (this.routlier !== undefined) {
+ result.push({ field: 'ro', value: this.routlier});
+ }
+ if (this.lwhisker !== undefined) {
+ result.push({ field: 'lw', value: this.lwhisker});
+ }
+ if (this.rwhisker !== undefined) {
+ result.push({ field: 'rw', value: this.rwhisker});
+ }
+ return result;
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ vlen = values.length,
+ options = this.options,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
+ maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
+ canvasLeft = 0,
+ lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
+ size, unitSize;
+
+ if (!box._super.render.call(this)) {
+ return;
+ }
+
+ if (options.get('raw')) {
+ if (options.get('showOutliers') && values.length > 5) {
+ loutlier = values[0];
+ lwhisker = values[1];
+ q1 = values[2];
+ q2 = values[3];
+ q3 = values[4];
+ rwhisker = values[5];
+ routlier = values[6];
+ } else {
+ lwhisker = values[0];
+ q1 = values[1];
+ q2 = values[2];
+ q3 = values[3];
+ rwhisker = values[4];
+ }
+ } else {
+ values.sort(function (a, b) { return a - b; });
+ q1 = quartile(values, 1);
+ q2 = quartile(values, 2);
+ q3 = quartile(values, 3);
+ iqr = q3 - q1;
+ if (options.get('showOutliers')) {
+ lwhisker = rwhisker = undefined;
+ for (i = 0; i < vlen; i++) {
+ if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
+ lwhisker = values[i];
+ }
+ if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
+ rwhisker = values[i];
+ }
+ }
+ loutlier = values[0];
+ routlier = values[vlen - 1];
+ } else {
+ lwhisker = values[0];
+ rwhisker = values[vlen - 1];
+ }
+ }
+ this.quartiles = [q1, q2, q3];
+ this.lwhisker = lwhisker;
+ this.rwhisker = rwhisker;
+ this.loutlier = loutlier;
+ this.routlier = routlier;
+
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (options.get('showOutliers')) {
+ canvasLeft = Math.ceil(options.get('spotRadius'));
+ canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (loutlier < lwhisker) {
+ target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ if (routlier > rwhisker) {
+ target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ }
+
+ // box
+ target.drawRect(
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q3 - q1) * unitSize),
+ Math.round(canvasHeight * 0.8),
+ options.get('boxLineColor'),
+ options.get('boxFillColor')).append();
+ // left whisker
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // right whisker
+ target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q3 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // median line
+ target.drawLine(
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.9),
+ options.get('medianColor')).append();
+ if (options.get('target')) {
+ size = Math.ceil(options.get('spotRadius'));
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) - size),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) + size),
+ options.get('targetColor')).append();
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
+ Math.round(canvasHeight / 2),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
+ Math.round(canvasHeight / 2),
+ options.get('targetColor')).append();
+ }
+ target.render();
+ }
+ });
+
+ // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
+ // This is accessible as $(foo).simpledraw()
+
+ // Detect browser renderer support
+ (function() {
+ if (document.namespaces && !document.namespaces.v) {
+ $.fn.sparkline.hasVML = true;
+ document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
+ } else {
+ $.fn.sparkline.hasVML = false;
+ }
+
+ var el = document.createElement('canvas');
+ $.fn.sparkline.hasCanvas = !!(el.getContext && el.getContext('2d'));
+
+ })()
+
+ VShape = createClass({
+ init: function (target, id, type, args) {
+ this.target = target;
+ this.id = id;
+ this.type = type;
+ this.args = args;
+ },
+ append: function () {
+ this.target.appendShape(this);
+ return this;
+ }
+ });
+
+ VCanvas_base = createClass({
+ _pxregex: /(\d+)(px)?\s*$/i,
+
+ init: function (width, height, target) {
+ if (!width) {
+ return;
+ }
+ this.width = width;
+ this.height = height;
+ this.target = target;
+ this.lastShapeId = null;
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ },
+
+ drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {
+ return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
+ },
+
+ drawShape: function (path, lineColor, fillColor, lineWidth) {
+ return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);
+ },
+
+ drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {
+ return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);
+ },
+
+ drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
+ },
+
+ drawRect: function (x, y, width, height, lineColor, fillColor) {
+ return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);
+ },
+
+ getElement: function () {
+ return this.canvas;
+ },
+
+ /**
+ * Return the most recently inserted shape id
+ */
+ getLastShapeId: function () {
+ return this.lastShapeId;
+ },
+
+ /**
+ * Clear and reset the canvas
+ */
+ reset: function () {
+ alert('reset not implemented');
+ },
+
+ _insert: function (el, target) {
+ $(target).html(el);
+ },
+
+ /**
+ * Calculate the pixel dimensions of the canvas
+ */
+ _calculatePixelDims: function (width, height, canvas) {
+ // XXX This should probably be a configurable option
+ var match;
+ match = this._pxregex.exec(height);
+ if (match) {
+ this.pixelHeight = match[1];
+ } else {
+ this.pixelHeight = $(canvas).height();
+ }
+ match = this._pxregex.exec(width);
+ if (match) {
+ this.pixelWidth = match[1];
+ } else {
+ this.pixelWidth = $(canvas).width();
+ }
+ },
+
+ /**
+ * Generate a shape object and id for later rendering
+ */
+ _genShape: function (shapetype, shapeargs) {
+ var id = shapeCount++;
+ shapeargs.unshift(id);
+ return new VShape(this, id, shapetype, shapeargs);
+ },
+
+ /**
+ * Add a shape to the end of the render queue
+ */
+ appendShape: function (shape) {
+ alert('appendShape not implemented');
+ },
+
+ /**
+ * Replace one shape with another
+ */
+ replaceWithShape: function (shapeid, shape) {
+ alert('replaceWithShape not implemented');
+ },
+
+ /**
+ * Insert one shape after another in the render queue
+ */
+ insertAfterShape: function (shapeid, shape) {
+ alert('insertAfterShape not implemented');
+ },
+
+ /**
+ * Remove a shape from the queue
+ */
+ removeShapeId: function (shapeid) {
+ alert('removeShapeId not implemented');
+ },
+
+ /**
+ * Find a shape at the specified x/y co-ordinates
+ */
+ getShapeAt: function (el, x, y) {
+ alert('getShapeAt not implemented');
+ },
+
+ /**
+ * Render all queued shapes onto the canvas
+ */
+ render: function () {
+ alert('render not implemented');
+ }
+ });
+
+ VCanvas_canvas = createClass(VCanvas_base, {
+ init: function (width, height, target, interact) {
+ VCanvas_canvas._super.init.call(this, width, height, target);
+ this.canvas = document.createElement('canvas');
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ this.interact = interact;
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});
+ },
+
+ _getContext: function (lineColor, fillColor, lineWidth) {
+ var context = this.canvas.getContext('2d');
+ if (lineColor !== undefined) {
+ context.strokeStyle = lineColor;
+ }
+ context.lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ if (fillColor !== undefined) {
+ context.fillStyle = fillColor;
+ }
+ return context;
+ },
+
+ reset: function () {
+ var context = this._getContext();
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth),
+ i, plen;
+ context.beginPath();
+ context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
+ for (i = 1, plen = path.length; i < plen; i++) {
+ context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth);
+ context.beginPath();
+ context.arc(x, y, radius, 0, 2 * Math.PI, false);
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var context = this._getContext(lineColor, fillColor);
+ context.beginPath();
+ context.moveTo(x, y);
+ context.arc(x, y, radius, startAngle, endAngle, false);
+ context.lineTo(x, y);
+ context.closePath();
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
+ },
+
+ appendShape: function (shape) {
+ this.shapes[shape.id] = shape;
+ this.shapeseq.push(shape.id);
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ this.shapes[shape.id] = shape;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] == shapeid) {
+ shapeseq[i] = shape.id;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ var shapeseq = this.shapeseq,
+ shapemap = {},
+ sid, i, first;
+
+ for (i = shapeids.length; i--;) {
+ shapemap[shapeids[i]] = true;
+ }
+ for (i = shapeseq.length; i--;) {
+ sid = shapeseq[i];
+ if (shapemap[sid]) {
+ shapeseq.splice(i, 1);
+ delete this.shapes[sid];
+ first = i;
+ }
+ }
+ for (i = shapes.length; i--;) {
+ shapeseq.splice(first, 0, shapes[i].id);
+ this.shapes[shapes[i].id] = shapes[i];
+ }
+
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i + 1, 0, shape.id);
+ this.shapes[shape.id] = shape;
+ return;
+ }
+ }
+ },
+
+ removeShapeId: function (shapeid) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i, 1);
+ break;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ getShapeAt: function (el, x, y) {
+ this.targetX = x;
+ this.targetY = y;
+ this.render();
+ return this.currentTargetShapeId;
+ },
+
+ render: function () {
+ var shapeseq = this.shapeseq,
+ shapes = this.shapes,
+ shapeCount = shapeseq.length,
+ context = this._getContext(),
+ shapeid, shape, i;
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ for (i = 0; i < shapeCount; i++) {
+ shapeid = shapeseq[i];
+ shape = shapes[shapeid];
+ this['_draw' + shape.type].apply(this, shape.args);
+ }
+ if (!this.interact) {
+ // not interactive so no need to keep the shapes array
+ this.shapes = {};
+ this.shapeseq = [];
+ }
+ }
+
+ });
+
+ VCanvas_vml = createClass(VCanvas_base, {
+ init: function (width, height, target) {
+ var groupel;
+ VCanvas_vml._super.init.call(this, width, height, target);
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ this.canvas = document.createElement('span');
+ $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ groupel = '';
+ this.canvas.insertAdjacentHTML('beforeEnd', groupel);
+ this.group = $(this.canvas).children()[0];
+ this.rendered = false;
+ this.prerender = '';
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var vpath = [],
+ initial, stroke, fill, closed, vel, plen, i;
+ for (i = 0, plen = path.length; i < plen; i++) {
+ vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);
+ }
+ initial = vpath.splice(0, 1);
+ lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';
+ vel = '' +
+ ' ';
+ return vel;
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var stroke, fill, vel;
+ x -= radius;
+ y -= radius;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '';
+ return vel;
+
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var vpath, startx, starty, endx, endy, stroke, fill, vel;
+ if (startAngle === endAngle) {
+ return ''; // VML seems to have problem when start angle equals end angle.
+ }
+ if ((endAngle - startAngle) === (2 * Math.PI)) {
+ startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0
+ endAngle = (2 * Math.PI);
+ }
+
+ startx = x + Math.round(Math.cos(startAngle) * radius);
+ starty = y + Math.round(Math.sin(startAngle) * radius);
+ endx = x + Math.round(Math.cos(endAngle) * radius);
+ endy = y + Math.round(Math.sin(endAngle) * radius);
+
+ if (startx === endx && starty === endy) {
+ if ((endAngle - startAngle) < Math.PI) {
+ // Prevent very small slices from being mistaken as a whole pie
+ return '';
+ }
+ // essentially going to be the entire circle, so ignore startAngle
+ startx = endx = x + radius;
+ starty = endy = y;
+ }
+
+ if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
+ return '';
+ }
+
+ vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '' +
+ ' ';
+ return vel;
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
+ },
+
+ reset: function () {
+ this.group.innerHTML = '';
+ },
+
+ appendShape: function (shape) {
+ var vel = this['_draw' + shape.type].apply(this, shape.args);
+ if (this.rendered) {
+ this.group.insertAdjacentHTML('beforeEnd', vel);
+ } else {
+ this.prerender += vel;
+ }
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].outerHTML = vel;
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ // replace the first shapeid with all the new shapes then toast the remaining old shapes
+ var existing = $('#jqsshape' + shapeids[0]),
+ replace = '',
+ slen = shapes.length,
+ i;
+ for (i = 0; i < slen; i++) {
+ replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
+ }
+ existing[0].outerHTML = replace;
+ for (i = 1; i < shapeids.length; i++) {
+ $('#jqsshape' + shapeids[i]).remove();
+ }
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].insertAdjacentHTML('afterEnd', vel);
+ },
+
+ removeShapeId: function (shapeid) {
+ var existing = $('#jqsshape' + shapeid);
+ this.group.removeChild(existing[0]);
+ },
+
+ getShapeAt: function (el, x, y) {
+ var shapeid = el.id.substr(8);
+ return shapeid;
+ },
+
+ render: function () {
+ if (!this.rendered) {
+ // batch the intial render into a single repaint
+ this.group.innerHTML = this.prerender;
+ this.rendered = true;
+ }
+ }
+ });
+
+}));
diff --git a/addons/crm/static/src/css/crm.css b/addons/crm/static/src/css/crm.css
index 3ad3840a4e1..ba4473edc26 100644
--- a/addons/crm/static/src/css/crm.css
+++ b/addons/crm/static/src/css/crm.css
@@ -20,15 +20,27 @@
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list {
- margin: 10px 0;
+ position: relative;
+ margin: 10px;
}
-.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a {
- width: 110px;
+.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div {
+ width: 160px;
+ height: 22px;
+ margin: 0 !important;
+ position: relative;
display: inline-block;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a:hover {
text-decoration: underline !important;
}
+.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div a:nth-child(2n) {
+ position: absolute;
+ left: 90px;
+ top: 0;
+}
+.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div:nth-child(2n) a:nth-child(2n) {
+ left: 110px;
+}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center {
text-align: center;
margin: 3px 0;
@@ -40,3 +52,13 @@
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_subsum {
font-size: 10px;
}
+
+.openerp .oe_kanban_view .oe_justgage {
+ color: black;
+ display: inline-block;
+}
+
+.openerp .oe_kanban_view .oe_sparkline_bar {
+ height: 20px;
+ width: 36px;
+}
\ No newline at end of file
diff --git a/addons/crm/static/src/js/crm.js b/addons/crm/static/src/js/crm.js
deleted file mode 100644
index e027313d6dc..00000000000
--- a/addons/crm/static/src/js/crm.js
+++ /dev/null
@@ -1,11 +0,0 @@
-openerp.crm = function(openerp) {
- openerp.web_kanban.KanbanRecord.include({
- on_card_clicked: function() {
- if (this.view.dataset.model === 'crm.case.section') {
- this.$('.oe_kanban_crm_salesteams_list a').first().click();
- } else {
- this._super.apply(this, arguments);
- }
- },
- });
-};
diff --git a/addons/crm/static/src/js/crm_case_section.js b/addons/crm/static/src/js/crm_case_section.js
new file mode 100644
index 00000000000..2b4ca741d75
--- /dev/null
+++ b/addons/crm/static/src/js/crm_case_section.js
@@ -0,0 +1,34 @@
+openerp.crm = function(openerp) {
+ openerp.web_kanban.KanbanRecord.include({
+ on_card_clicked: function() {
+ if (this.view.dataset.model === 'crm.case.section') {
+ this.$('.oe_kanban_crm_salesteams_list a').first().click();
+ } else {
+ this._super.apply(this, arguments);
+ }
+ },
+ });
+
+ openerp.crm.SparklineBarWidget = openerp.web_kanban.AbstractField.extend({
+ className: "oe_sparkline_bar",
+ start: function() {
+ var self = this;
+ var title = this.$node.html();
+ setTimeout(function () {
+ var value = _.pluck(self.field.value, 'value');
+ var tooltips = _.pluck(self.field.value, 'tooltip');
+ self.$el.sparkline(value, {
+ type: 'bar',
+ barWidth: 5,
+ tooltipFormat: '{{offset:offset}} {{value}}',
+ tooltipValueLookups: {
+ 'offset': tooltips
+ },
+ });
+ self.$el.tipsy({'delayIn': 0, 'html': true, 'title': function(){return title}, 'gravity': 'n'});
+ }, 0);
+ },
+ });
+ openerp.web_kanban.fields_registry.add("sparkline_bar", "openerp.crm.SparklineBarWidget");
+
+};
diff --git a/addons/crm/test/crm_lead_cancel.yml b/addons/crm/test/crm_lead_cancel.yml
index edaf844952a..0f8d9ba1df9 100644
--- a/addons/crm/test/crm_lead_cancel.yml
+++ b/addons/crm/test/crm_lead_cancel.yml
@@ -1,38 +1,9 @@
-
- I cancel unqualified lead.
+ I set a new sale team (with Marketing at parent) and I cancel unqualified lead .
-
!python {model: crm.lead}: |
- self.case_cancel(cr, uid, [ref("crm_case_1")])
--
- I check cancelled lead.
--
- !python {model: crm.lead}: |
- lead = self.browse(cr, uid, ref('crm_case_1'))
- assert lead.stage_id.id == ref('crm.stage_lead7'), "Stage should be 'Dead' and is %s." % (lead.stage_id.name)
- assert lead.state == 'cancel', "Opportunity is not in 'cancel' state."
- assert lead.probability == 0.0, 'Opportunity is probably wrong and should be 0.0.'
--
- I reset cancelled lead into unqualified lead.
--
- !python {model: crm.lead}: |
- self.case_reset(cr, uid, [ref("crm_case_1")])
--
- I check unqualified lead after reset.
--
- !assert {model: crm.lead, id: crm.crm_case_1, string: Lead is in draft state}:
- - state == "draft"
--
- I re-open the lead
--
- !python {model: crm.lead}: |
- self.case_open(cr, uid, [ref("crm_case_1")])
--
- I check stage and state of the re-opened lead
--
- !python {model: crm.lead}: |
- lead = self.browse(cr, uid, ref('crm.crm_case_1'))
- assert lead.stage_id.id == ref('crm.stage_lead2'), "Opportunity stage should be 'Qualification'."
- assert lead.state == 'open', "Opportunity should be in 'open' state."
+ section_id = self.pool.get('crm.case.section').create(cr, uid, {'name': "Phone Marketing", 'parent_id': ref("crm.crm_case_section_2")})
+ self.write(cr, uid, [ref("crm_case_1")], {'section_id': section_id})
-
I escalate the lead to parent team.
-
@@ -42,4 +13,4 @@
I check the lead is correctly escalated to the parent team.
-
!assert {model: crm.lead, id: crm.crm_case_1, string: Escalate lead to parent team}:
- - section_id.name == "Support Department"
+ - section_id.name == "Marketing"
diff --git a/addons/crm/test/crm_lead_onchange.yml b/addons/crm/test/crm_lead_onchange.yml
index 9154ffdf513..45e140e890e 100644
--- a/addons/crm/test/crm_lead_onchange.yml
+++ b/addons/crm/test/crm_lead_onchange.yml
@@ -20,9 +20,4 @@
-
!record {model: crm.phonecall, id: crm_phonecall_5}:
name: 'Bad time'
- partner_id: base.res_partner_5
--
- I set the next stage to "New" for the lead.
--
- !python {model: crm.lead}: |
- self.stage_next(cr, uid, [ref("crm_case_4")], context={'stage_type': 'lead'})
+ partner_id: base.res_partner_5
\ No newline at end of file
diff --git a/addons/crm/test/lead2opportunity2win.yml b/addons/crm/test/lead2opportunity2win.yml
index 94e7149ef77..23545c61bc1 100644
--- a/addons/crm/test/lead2opportunity2win.yml
+++ b/addons/crm/test/lead2opportunity2win.yml
@@ -1,25 +1,15 @@
-
In order to test the conversion of a lead into a opportunity,
--
- I open a lead.
--
- !python {model: crm.lead}: |
- self.case_open(cr, uid, [ref("crm_case_4")])
--
- I check if the lead state is "Open".
--
- !assert {model: crm.lead, id: crm.crm_case_4, string: Lead state is Open}:
- - state == "open"
-
I convert lead into opportunity for exiting customer.
-
!python {model: crm.lead}: |
- self.convert_opportunity(cr, uid ,[ref("crm_case_4")], ref("base.res_partner_2"))
+ self.convert_opportunity(cr, uid ,[ref("crm_case_1")], ref("base.res_partner_2"))
-
I check details of converted opportunity.
-
!python {model: crm.lead}: |
- lead = self.browse(cr, uid, ref('crm_case_4'))
+ lead = self.browse(cr, uid, ref('crm_case_1'))
assert lead.type == 'opportunity', 'Lead is not converted to opportunity!'
assert lead.partner_id.id == ref("base.res_partner_2"), 'Partner mismatch!'
assert lead.stage_id.id == ref("stage_lead1"), 'Stage of opportunity is incorrect!'
@@ -28,7 +18,7 @@
-
!python {model: crm.opportunity2phonecall}: |
import time
- context.update({'active_model': 'crm.lead', 'active_ids': [ref('crm_case_4')]})
+ context.update({'active_model': 'crm.lead', 'active_ids': [ref('crm_case_1')]})
call_id = self.create(cr, uid, {'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'name': "Bonjour M. Jean, Comment allez-vous? J'ai bien reçu votre demande, pourrions-nous en parler quelques minutes?"}, context=context)
self.action_schedule(cr, uid, [call_id], context=context)
@@ -36,28 +26,28 @@
I check that phonecall is scheduled for that opportunity.
-
!python {model: crm.phonecall}: |
- ids = self.search(cr, uid, [('opportunity_id', '=', ref('crm_case_4'))])
+ ids = self.search(cr, uid, [('opportunity_id', '=', ref('crm_case_1'))])
assert len(ids), 'Phonecall is not scheduled'
-
Now I schedule meeting with customer.
-
!python {model: crm.lead}: |
- self.action_makeMeeting(cr, uid, [ref('crm_case_4')])
+ self.action_makeMeeting(cr, uid, [ref('crm_case_1')])
-
After communicated with customer, I put some notes with contract details.
-
!python {model: crm.lead}: |
- self.message_post(cr, uid, [ref('crm_case_4')], subject='Test note', body='Détails envoyés par le client sur le FAX pour la qualité')
+ self.message_post(cr, uid, [ref('crm_case_1')], subject='Test note', body='Détails envoyés par le client sur le FAX pour la qualité')
-
I win this opportunity
-
!python {model: crm.lead}: |
- self.case_mark_won(cr, uid, [ref("crm_case_4")])
+ self.case_mark_won(cr, uid, [ref("crm_case_1")])
-
I check details of the opportunity after having won the opportunity.
-
!python {model: crm.lead}: |
- lead = self.browse(cr, uid, ref('crm_case_4'))
+ lead = self.browse(cr, uid, ref('crm_case_1'))
assert lead.stage_id.id == ref('crm.stage_lead6'), "Opportunity stage should be 'Won'."
assert lead.state == 'done', "Opportunity is not in 'done' state!"
assert lead.probability == 100.0, "Revenue probability should be 100.0!"
@@ -104,7 +94,6 @@
-
!python {model: crm.meeting}: |
context.update({'active_model': 'crm.meeting'})
- self.case_open(cr, uid, [ref('base_calendar.crm_meeting_4')])
-
I invite a user for meeting.
-
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/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py
index e67b7c0c7be..3c847ade42a 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity.py
+++ b/addons/crm/wizard/crm_lead_to_opportunity.py
@@ -86,7 +86,7 @@ class crm_lead2opportunity_partner(osv.osv_memory):
lead_obj = self.pool.get('crm.lead')
for lead in lead_obj.browse(cr, uid, context.get('active_ids', []), context=context):
if lead.state in ['done', 'cancel']:
- raise osv.except_osv(_("Warning !"), _("Closed/Cancelled leads cannot be converted into opportunities."))
+ raise osv.except_osv(_("Warning!"), _("Closed/Cancelled leads cannot be converted into opportunities."))
return False
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
index 4093df910d0..9ddd1fc701f 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
@@ -102,7 +102,9 @@
res_model="crm.lead2opportunity.partner.mass" src_model="crm.lead"
view_mode="form" target="new" view_type="form"
context="{'mass_convert' : True}"
- view_id="view_crm_lead2opportunity_partner_mass"/>
+ view_id="view_crm_lead2opportunity_partner_mass"
+ groups="base.group_sale_salesman"
+ />
diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml
index 919d83cb9a7..60693c13e19 100644
--- a/addons/crm/wizard/crm_merge_opportunities_view.xml
+++ b/addons/crm/wizard/crm_merge_opportunities_view.xml
@@ -45,7 +45,9 @@
multi="True"
key2="client_action_multi" name="Merge leads/opportunities"
res_model="crm.merge.opportunity" src_model="crm.lead"
- view_mode="form" target="new" view_type="form"/>
+ view_mode="form" target="new" view_type="form"
+ groups="base.group_sale_salesman"
+ />
diff --git a/addons/crm_claim/__openerp__.py b/addons/crm_claim/__openerp__.py
index 61257265f1b..eaec2e4fc2b 100644
--- a/addons/crm_claim/__openerp__.py
+++ b/addons/crm_claim/__openerp__.py
@@ -42,14 +42,20 @@ automatically new claims based on incoming emails.
'security/ir.model.access.csv',
'report/crm_claim_report_view.xml',
'crm_claim_data.xml',
+ 'res_partner_view.xml',
],
'demo': ['crm_claim_demo.xml'],
- 'test': ['test/process/claim.yml',
- 'test/ui/claim_demo.yml'
+ 'test': [
+ 'test/process/claim.yml',
+ 'test/ui/claim_demo.yml'
],
'installable': True,
'auto_install': False,
- 'images': ['images/claim_categories.jpeg','images/claim_stages.jpeg','images/claims.jpeg'],
+ 'images': [
+ 'images/claim_categories.jpeg',
+ 'images/claim_stages.jpeg',
+ 'images/claims.jpeg'
+ ],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 275d9edaab4..1e3ed2faad1 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -19,20 +19,12 @@
#
##############################################################################
-from openerp.addons.base_status.base_stage import base_stage
-import binascii
from openerp.addons.crm import crm
from openerp.osv import fields, osv
-import time
from openerp import tools
from openerp.tools.translate import _
from openerp.tools import html2plaintext
-CRM_CLAIM_PENDING_STATES = (
- crm.AVAILABLE_STATES[2][0], # Cancelled
- crm.AVAILABLE_STATES[3][0], # Done
- crm.AVAILABLE_STATES[4][0], # Pending
-)
class crm_claim_stage(osv.osv):
""" Model for claim stages. This models the main stages of a claim
@@ -51,8 +43,6 @@ class crm_claim_stage(osv.osv):
'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections',
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
'state': fields.selection(crm.AVAILABLE_STATES, 'Status', required=True, help="The related status for the stage. The status of your document will automatically change regarding the selected stage. For example, if a stage is related to the status 'Close', when your document reaches this stage, it will be automatically have the 'closed' status."),
- 'case_refused': fields.boolean('Refused stage',
- help='Refused stages are specific stages for done.'),
'case_default': fields.boolean('Common to All Teams',
help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
'fold': fields.boolean('Hide in Views when Empty',
@@ -63,10 +53,9 @@ class crm_claim_stage(osv.osv):
'sequence': lambda *args: 1,
'state': 'draft',
'fold': False,
- 'case_refused': False,
}
-class crm_claim(base_stage, osv.osv):
+class crm_claim(osv.osv):
""" Crm claim
"""
_name = "crm.claim"
@@ -74,6 +63,15 @@ class crm_claim(base_stage, osv.osv):
_order = "priority,date desc"
_inherit = ['mail.thread']
+ def _get_default_section_id(self, cr, uid, context=None):
+ """ Gives default section by checking if present in the context """
+ return self.pool.get('crm.lead')._resolve_section_id_from_context(cr, uid, context=context) or False
+
+ def _get_default_stage_id(self, cr, uid, context=None):
+ """ Gives default stage_id """
+ section_id = self._get_default_section_id(cr, uid, context=context)
+ return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft')], context=context)
+
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Claim Subject', size=128, required=True),
@@ -105,7 +103,7 @@ class crm_claim(base_stage, osv.osv):
'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.claim.stage', 'Stage', track_visibility='onchange',
- domain="['&',('fold', '=', False),'|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
+ domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
'cause': fields.text('Root Cause'),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
@@ -117,15 +115,13 @@ class crm_claim(base_stage, osv.osv):
}
_defaults = {
- 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
- 'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
- 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
+ 'user_id': lambda s, cr, uid, c: uid,
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
- 'date': fields.datetime.now,
+ 'date': fields.datetime.now(),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'active': lambda *a: 1,
- 'stage_id':lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
+ 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
}
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
@@ -158,27 +154,24 @@ class crm_claim(base_stage, osv.osv):
return stage_ids[0]
return False
- def case_refuse(self, cr, uid, ids, context=None):
- """ Mark the case as refused: state=done and case_refused=True """
- for lead in self.browse(cr, uid, ids):
- stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, ['&', ('state', '=', 'done'), ('case_refused', '=', True)], context=context)
- if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={}, new_stage_id=stage_id, context=context)
- return True
-
- def onchange_partner_id(self, cr, uid, ids, part, email=False):
+ def onchange_partner_id(self, cr, uid, ids, partner_id, email=False, context=None):
"""This function returns value of partner address based on partner
- :param part: Partner's id
:param email: ignored
"""
- if not part:
- return {'value': {'email_from': False,
- 'partner_phone': False
- }
- }
- address = self.pool.get('res.partner').browse(cr, uid, part)
+ if not partner_id:
+ return {'value': {'email_from': False, 'partner_phone': False}}
+ address = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if vals.get('section_id') and not context.get('default_section_id'):
+ context['default_section_id'] = vals.get('section_id')
+
+ # context: no_log, because subtype already handle this
+ return super(crm_claim, self).create(cr, uid, vals, context=context)
+
# -------------------------------------------------------
# Mail gateway
# -------------------------------------------------------
diff --git a/addons/crm_claim/crm_claim_menu.xml b/addons/crm_claim/crm_claim_menu.xml
index 5abfcabbc71..59ec2acac2f 100644
--- a/addons/crm_claim/crm_claim_menu.xml
+++ b/addons/crm_claim/crm_claim_menu.xml
@@ -15,7 +15,11 @@
{"search_default_user_id":uid, "stage_type":'claim'}
- Record and track your customers' claims. Claims may be linked to a sales order or a lot. You can send emails with attachments and keep the full history for a claim (emails sent, intervention type and so on). Claims may automatically be linked to an email address using the mail gateway module.
+
+
+ Record and track your customers' claims. Claims may be linked to a sales order or a lot.You can send emails with attachments and keep the full history for a claim (emails sent, intervention type and so on).Claims may automatically be linked to an email address using the mail gateway module.
+
+
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml
index e295bfdd250..28d0f7c731c 100644
--- a/addons/crm_claim/crm_claim_view.xml
+++ b/addons/crm_claim/crm_claim_view.xml
@@ -52,7 +52,6 @@
-
@@ -102,10 +101,6 @@
-
-
- res.partner.claim.info.form
- res.partner
-
- 20
-
-
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/crm_claim/i18n/ru.po b/addons/crm_claim/i18n/ru.po
index afcf4702a67..4579b6d8557 100644
--- a/addons/crm_claim/i18n/ru.po
+++ b/addons/crm_claim/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-10-24 05:01+0000\n"
+"PO-Revision-Date: 2013-05-30 14:03+0000\n"
"Last-Translator: Chertykov Denis \n"
"Language-Team: Russian \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:44+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-05-31 05:38+0000\n"
+"X-Generator: Launchpad (build 16660)\n"
#. module: crm_claim
#: help:crm.claim.stage,fold:0
@@ -23,6 +23,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 ""
+"Эта стадия не видима, например в статус-баре или виде канбан, когда нет "
+"записей этой стадии для отображения."
#. module: crm_claim
#: field:crm.claim.report,nbr:0
@@ -46,11 +48,13 @@ msgid ""
"Allows you to configure your incoming mail server, and create claims from "
"incoming emails."
msgstr ""
+"Позволяет настроить сервер входящей почты и создавать претензии из входящих "
+"эл. писем."
#. module: crm_claim
#: model:ir.model,name:crm_claim.model_crm_claim_stage
msgid "Claim stages"
-msgstr ""
+msgstr "Этапы претензии"
#. module: crm_claim
#: selection:crm.claim.report,month:0
@@ -65,7 +69,7 @@ msgstr "Задержка закрытия"
#. module: crm_claim
#: field:crm.claim,message_unread:0
msgid "Unread Messages"
-msgstr ""
+msgstr "Непрочитанные"
#. module: crm_claim
#: field:crm.claim,resolution:0
@@ -100,12 +104,12 @@ msgstr "# претензий"
#. module: crm_claim
#: field:crm.claim.stage,name:0
msgid "Stage Name"
-msgstr ""
+msgstr "Название этапа"
#. module: crm_claim
#: view:crm.claim.report:0
msgid "Salesperson"
-msgstr ""
+msgstr "Продавец"
#. module: crm_claim
#: selection:crm.claim,priority:0
@@ -149,7 +153,7 @@ msgstr "Предупредительная мера"
#. module: crm_claim
#: help:crm.claim,message_unread:0
msgid "If checked new messages require your attention."
-msgstr ""
+msgstr "Если отмечено, новые сообщения требуют вашего внимания."
#. module: crm_claim
#: field:crm.claim.report,date_closed:0
@@ -182,6 +186,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 ""
+"Содержит сводку по Чаттеру (количество сообщений,...). Эта сводка в формате "
+"html для возможности использования в канбан виде"
#. module: crm_claim
#: view:crm.claim:0
@@ -235,12 +241,12 @@ msgstr "Важность"
#. module: crm_claim
#: field:crm.claim.stage,fold:0
msgid "Hide in Views when Empty"
-msgstr ""
+msgstr "Скрыть вид, если пусто"
#. module: crm_claim
#: field:crm.claim,message_follower_ids:0
msgid "Followers"
-msgstr ""
+msgstr "Подписчики"
#. module: crm_claim
#: view:crm.claim:0
@@ -254,7 +260,7 @@ msgstr "Новый"
#. module: crm_claim
#: field:crm.claim.stage,section_ids:0
msgid "Sections"
-msgstr ""
+msgstr "Секции"
#. module: crm_claim
#: field:crm.claim,email_from:0
@@ -290,7 +296,7 @@ msgstr "Предмет претензии"
#. module: crm_claim
#: model:crm.claim.stage,name:crm_claim.stage_claim3
msgid "Rejected"
-msgstr ""
+msgstr "Отклонено"
#. module: crm_claim
#: field:crm.claim,date_action_next:0
@@ -344,7 +350,7 @@ msgstr ""
#: code:addons/crm_claim/crm_claim.py:194
#, python-format
msgid "No Subject"
-msgstr ""
+msgstr "Без темы"
#. module: crm_claim
#: help:crm.claim.stage,state:0
@@ -358,7 +364,7 @@ msgstr ""
#. module: crm_claim
#: view:crm.claim:0
msgid "Settle"
-msgstr ""
+msgstr "Решать"
#. module: crm_claim
#: model:ir.ui.menu,name:crm_claim.menu_claim_stage_view
@@ -384,7 +390,7 @@ msgstr "Отчет о претензиях"
#. module: crm_claim
#: view:sale.config.settings:0
msgid "Configure"
-msgstr ""
+msgstr "Настроить"
#. module: crm_claim
#: model:crm.case.resource.type,name:crm_claim.type_claim1
@@ -430,6 +436,8 @@ msgid ""
"If you check this field, this stage will be proposed by default on each "
"sales team. It will not assign this stage to existing teams."
msgstr ""
+"Если вы отметите это поле, этот этап будет предложен по умолчанию каждому "
+"отделу продаж. Этот этап не будет назначен существующим отделам."
#. module: crm_claim
#: field:crm.claim,categ_id:0
@@ -485,7 +493,7 @@ msgstr "Закрыто"
#. module: crm_claim
#: view:crm.claim:0
msgid "Reject"
-msgstr ""
+msgstr "Отклонить"
#. module: crm_claim
#: view:res.partner:0
@@ -495,7 +503,7 @@ msgstr "Претензии партнера"
#. module: crm_claim
#: view:crm.claim.stage:0
msgid "Claim Stage"
-msgstr ""
+msgstr "Этап претензии"
#. module: crm_claim
#: view:crm.claim:0
@@ -513,7 +521,7 @@ msgstr "Отложено"
#: field:crm.claim.report,state:0
#: field:crm.claim.stage,state:0
msgid "Status"
-msgstr ""
+msgstr "Статус"
#. module: crm_claim
#: selection:crm.claim.report,month:0
@@ -529,7 +537,7 @@ msgstr "Обычный"
#. module: crm_claim
#: help:crm.claim.stage,sequence:0
msgid "Used to order stages. Lower is better."
-msgstr ""
+msgstr "Используется для упорядочивания этапов. Меньше - лучше."
#. module: crm_claim
#: selection:crm.claim.report,month:0
@@ -549,7 +557,7 @@ msgstr "Телефон"
#. module: crm_claim
#: field:crm.claim,message_is_follower:0
msgid "Is a Follower"
-msgstr ""
+msgstr "Подписан"
#. module: crm_claim
#: field:crm.claim.report,user_id:0
@@ -581,6 +589,10 @@ msgid ""
"the case needs to be reviewed then the status is set "
"to 'Pending'."
msgstr ""
+"Статус устанавливается в \"Черновик\", при создании дела. Если дело в "
+"процессе, то статус - «Открыт». Когда дело закончено, устанавливается статус "
+"\"Готово\". Если дело должно быть пересмотрено то статус установлен в "
+"'Ожидание'."
#. module: crm_claim
#: field:crm.claim,active:0
@@ -628,7 +640,7 @@ msgstr "Дата претензии"
#. module: crm_claim
#: field:crm.claim,message_summary:0
msgid "Summary"
-msgstr ""
+msgstr "Итог"
#. module: crm_claim
#: model:ir.actions.act_window,name:crm_claim.crm_claim_categ_action
@@ -638,7 +650,7 @@ msgstr "Категории претензий"
#. module: crm_claim
#: field:crm.claim.stage,case_default:0
msgid "Common to All Teams"
-msgstr ""
+msgstr "Общее для всех отделов"
#. module: crm_claim
#: view:crm.claim:0
@@ -677,7 +689,7 @@ msgstr "Претензия"
#. module: crm_claim
#: view:crm.claim.report:0
msgid "My Company"
-msgstr ""
+msgstr "Моя компания"
#. module: crm_claim
#: view:crm.claim.report:0
@@ -807,7 +819,7 @@ msgstr "Февраль"
#. module: crm_claim
#: model:ir.model,name:crm_claim.model_sale_config_settings
msgid "sale.config.settings"
-msgstr ""
+msgstr "sale.config.settings"
#. module: crm_claim
#: view:crm.claim.report:0
@@ -833,22 +845,22 @@ msgstr "Мои дела"
#. module: crm_claim
#: model:crm.claim.stage,name:crm_claim.stage_claim2
msgid "Settled"
-msgstr ""
+msgstr "Решено"
#. module: crm_claim
#: help:crm.claim,message_ids:0
msgid "Messages and communication history"
-msgstr ""
+msgstr "Сообщения и история общения"
#. module: crm_claim
#: field:sale.config.settings,fetchmail_claim:0
msgid "Create claims from incoming mails"
-msgstr ""
+msgstr "Создать претензии из входящей почты"
#. module: crm_claim
#: field:crm.claim.stage,sequence:0
msgid "Sequence"
-msgstr ""
+msgstr "Нумерация"
#. module: crm_claim
#: view:crm.claim:0
@@ -883,6 +895,8 @@ msgid ""
"Link between stages and sales teams. When set, this limitate the current "
"stage to the selected sales teams."
msgstr ""
+"Связь между этапами и отделами продаж. При установке, ограничивает этап для "
+"выбранного отдела продаж."
#. module: crm_claim
#: help:crm.claim.stage,case_refused:0
diff --git a/addons/crm_claim/report/crm_claim_report_view.xml b/addons/crm_claim/report/crm_claim_report_view.xml
index 530eb6061a3..bae02ef8c0c 100644
--- a/addons/crm_claim/report/crm_claim_report_view.xml
+++ b/addons/crm_claim/report/crm_claim_report_view.xml
@@ -55,7 +55,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/addons/crm_claim/res_partner_view.xml b/addons/crm_claim/res_partner_view.xml
new file mode 100644
index 00000000000..4a5db879311
--- /dev/null
+++ b/addons/crm_claim/res_partner_view.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ res.partner.claim.info.form
+ res.partner
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm_claim/test/process/claim.yml b/addons/crm_claim/test/process/claim.yml
index a843372956e..f6c6f6d315c 100644
--- a/addons/crm_claim/test/process/claim.yml
+++ b/addons/crm_claim/test/process/claim.yml
@@ -21,25 +21,9 @@
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')])
- self.case_open(cr, uid, claim_ids)
-
- I check Claim Details after open.
+ I check Claim Details after open.
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')])
claim = self.browse(cr, uid, claim_ids[0])
- assert claim.state == "open", "Claim is not in Open state"
- assert claim.stage_id.id == ref("crm.stage_lead2"), "Claim is not in Qualification stage"
--
- After complete all service from our side, I close this claim.
--
- !python {model: crm.claim}: |
- claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')])
- self.case_close(cr, uid, claim_ids)
--
- I check Claim details after closed.
--
- !python {model: crm.claim}: |
- claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')])
- claim = self.browse(cr, uid, claim_ids[0])
- assert claim.state == "done", "Claim is not in close state"
diff --git a/addons/crm_helpdesk/crm_helpdesk.py b/addons/crm_helpdesk/crm_helpdesk.py
index 2d0383962b1..ea58016b4c1 100644
--- a/addons/crm_helpdesk/crm_helpdesk.py
+++ b/addons/crm_helpdesk/crm_helpdesk.py
@@ -20,20 +20,14 @@
##############################################################################
from openerp.addons.base_status.base_state import base_state
-from openerp.addons.base_status.base_stage import base_stage
from openerp.addons.crm import crm
from openerp.osv import fields, osv
from openerp import tools
from openerp.tools.translate import _
from openerp.tools import html2plaintext
-CRM_HELPDESK_STATES = (
- crm.AVAILABLE_STATES[2][0], # Cancelled
- crm.AVAILABLE_STATES[3][0], # Done
- crm.AVAILABLE_STATES[4][0], # Pending
-)
-class crm_helpdesk(base_state, base_stage, osv.osv):
+class crm_helpdesk(base_state, osv.osv):
""" Helpdesk Cases """
_name = "crm.helpdesk"
@@ -80,9 +74,7 @@ class crm_helpdesk(base_state, base_stage, osv.osv):
_defaults = {
'active': lambda *a: 1,
- 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
- 'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
- 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
+ 'user_id': lambda s, cr, uid, c: uid,
'state': lambda *a: 'draft',
'date': lambda *a: fields.datetime.now(),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
diff --git a/addons/crm_helpdesk/crm_helpdesk_view.xml b/addons/crm_helpdesk/crm_helpdesk_view.xml
index 6e3521be6f2..f97fe654166 100644
--- a/addons/crm_helpdesk/crm_helpdesk_view.xml
+++ b/addons/crm_helpdesk/crm_helpdesk_view.xml
@@ -151,14 +151,14 @@
+ help="Helpdesk requests that are assigned to me or to one of the sale teams I manage" groups="base.group_multi_salesteams"/>
-
+
diff --git a/addons/crm_helpdesk/i18n/ru.po b/addons/crm_helpdesk/i18n/ru.po
index e8eb90af9d7..bb53c03294f 100644
--- a/addons/crm_helpdesk/i18n/ru.po
+++ b/addons/crm_helpdesk/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-10-24 05:08+0000\n"
+"PO-Revision-Date: 2013-05-30 14:09+0000\n"
"Last-Translator: Chertykov Denis \n"
"Language-Team: Russian \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:46+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-05-31 05:38+0000\n"
+"X-Generator: Launchpad (build 16660)\n"
#. module: crm_helpdesk
#: field:crm.helpdesk.report,delay_close:0
@@ -46,7 +46,7 @@ msgstr "Март"
#. module: crm_helpdesk
#: field:crm.helpdesk,message_unread:0
msgid "Unread Messages"
-msgstr ""
+msgstr "Непрочитанные"
#. module: crm_helpdesk
#: field:crm.helpdesk,company_id:0
@@ -63,7 +63,7 @@ msgstr "Адреса наблюдателей"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "Salesperson"
-msgstr ""
+msgstr "Продавец"
#. module: crm_helpdesk
#: selection:crm.helpdesk,priority:0
@@ -106,7 +106,7 @@ msgstr "Отменено"
#. module: crm_helpdesk
#: help:crm.helpdesk,message_unread:0
msgid "If checked new messages require your attention."
-msgstr ""
+msgstr "Если отмечено, новые сообщения требуют вашего внимания."
#. module: crm_helpdesk
#: model:ir.actions.act_window,name:crm_helpdesk.action_report_crm_helpdesk
@@ -136,6 +136,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 ""
+"Содержит сводку по Чаттеру (количество сообщений,...). Эта сводка в формате "
+"html для возможности использования в канбан виде"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@@ -176,7 +178,7 @@ msgstr "Приоритет"
#. module: crm_helpdesk
#: field:crm.helpdesk,message_follower_ids:0
msgid "Followers"
-msgstr ""
+msgstr "Подписчики"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@@ -400,7 +402,7 @@ msgstr "В ожидании"
#: view:crm.helpdesk.report:0
#: field:crm.helpdesk.report,state:0
msgid "Status"
-msgstr ""
+msgstr "Статус"
#. module: crm_helpdesk
#: selection:crm.helpdesk.report,month:0
@@ -454,7 +456,7 @@ msgstr "Планируемая выручка"
#. module: crm_helpdesk
#: field:crm.helpdesk,message_is_follower:0
msgid "Is a Follower"
-msgstr ""
+msgstr "Подписан"
#. module: crm_helpdesk
#: field:crm.helpdesk.report,user_id:0
@@ -501,7 +503,7 @@ msgstr "Январь"
#. module: crm_helpdesk
#: field:crm.helpdesk,message_summary:0
msgid "Summary"
-msgstr ""
+msgstr "Итог"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@@ -517,7 +519,7 @@ msgstr "Прочее"
#. module: crm_helpdesk
#: view:crm.helpdesk.report:0
msgid "My Company"
-msgstr ""
+msgstr "Моя компания"
#. module: crm_helpdesk
#: view:crm.helpdesk:0
@@ -666,7 +668,7 @@ msgstr ""
#. module: crm_helpdesk
#: help:crm.helpdesk,message_ids:0
msgid "Messages and communication history"
-msgstr ""
+msgstr "Сообщения и история общения"
#. module: crm_helpdesk
#: model:ir.actions.act_window,help:crm_helpdesk.crm_helpdesk_categ_action
diff --git a/addons/crm_helpdesk/i18n/zh_CN.po b/addons/crm_helpdesk/i18n/zh_CN.po
index 4a80e7f9385..13843f911c9 100644
--- a/addons/crm_helpdesk/i18n/zh_CN.po
+++ b/addons/crm_helpdesk/i18n/zh_CN.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:05+0000\n"
-"PO-Revision-Date: 2012-12-14 13:33+0000\n"
-"Last-Translator: 盈通 ccdos \n"
+"PO-Revision-Date: 2013-06-07 05:02+0000\n"
+"Last-Translator: PeterGao <306739889@qq.com>\n"
"Language-Team: Chinese (Simplified) \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:46+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-06-08 05:52+0000\n"
+"X-Generator: Launchpad (build 16667)\n"
#. module: crm_helpdesk
#: field:crm.helpdesk.report,delay_close:0
@@ -656,6 +656,12 @@ msgid ""
" \n"
"If the case needs to be reviewed then the status is set to 'Pending'."
msgstr ""
+"当一个“case(事件)\"被新创建后,这个“case(事件)\"的状态为“草稿”状态。 "
+" \n"
+"若这个“case(事件)\"正在处理中,这个“case(事件)\"的状态为“开启”状态。\n"
+"若这个“case(事件)\"已处理完结,这个“case(事件)\"的状态为“结单”状态。 "
+" \n"
+"若这个“case(事件)\"需暂停再议,这个“case(事件)\"的状态为“挂起”状态。"
#. module: crm_helpdesk
#: help:crm.helpdesk,message_ids:0
diff --git a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
index 6ce2c60093f..c1ffc00303d 100644
--- a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
+++ b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
@@ -56,7 +56,7 @@
-
+
@@ -71,7 +71,7 @@
-
+
diff --git a/addons/crm_helpdesk/test/customer_question.eml b/addons/crm_helpdesk/test/customer_question.eml
index 38a4c95fb0c..9bc7c91cb41 100644
--- a/addons/crm_helpdesk/test/customer_question.eml
+++ b/addons/crm_helpdesk/test/customer_question.eml
@@ -3,7 +3,7 @@ Date: Tue, 25 Oct 2011 13:41:17 +0530
From: Mr. John Right
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
MIME-Version: 1.0
-To: info@my.com
+To: _helpdesk@my.com
Subject: Where is download link of user manual of your product ?
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
diff --git a/addons/crm_partner_assign/__init__.py b/addons/crm_partner_assign/__init__.py
index bb4a3bb53be..6b1315cef07 100644
--- a/addons/crm_partner_assign/__init__.py
+++ b/addons/crm_partner_assign/__init__.py
@@ -20,6 +20,7 @@
##############################################################################
import crm_partner_assign
+import crm_lead
import wizard
import report
diff --git a/addons/crm_partner_assign/__openerp__.py b/addons/crm_partner_assign/__openerp__.py
index b9b21ca7a6a..37a8c5a3d6b 100644
--- a/addons/crm_partner_assign/__openerp__.py
+++ b/addons/crm_partner_assign/__openerp__.py
@@ -37,17 +37,23 @@ The most appropriate partner can be assigned.
You can also use the geolocalization without using the GPS coordinates.
""",
'author': 'OpenERP SA',
- 'depends': ['crm', 'account'],
+ 'depends': ['crm', 'account', 'portal'],
'demo': ['res_partner_demo.xml'],
'data': [
'security/ir.model.access.csv',
'res_partner_view.xml',
'wizard/crm_forward_to_partner_view.xml',
+ 'wizard/crm_channel_interested_view.xml',
'crm_lead_view.xml',
'crm_partner_assign_data.xml',
+ 'crm_portal_view.xml',
+ 'portal_data.xml',
'report/crm_lead_report_view.xml',
'report/crm_partner_report_view.xml',
],
+ 'js': [
+ 'static/src/js/next.js',
+ ],
'test': ['test/partner_assign.yml'],
'installable': True,
'auto_install': False,
diff --git a/addons/crm_partner_assign/crm_lead.py b/addons/crm_partner_assign/crm_lead.py
new file mode 100644
index 00000000000..37f4b9aedff
--- /dev/null
+++ b/addons/crm_partner_assign/crm_lead.py
@@ -0,0 +1,44 @@
+# -*- 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 .
+#
+##############################################################################
+
+from openerp.osv import osv
+from openerp.tools.translate import _
+
+
+class crm_lead(osv.osv):
+ _inherit = 'crm.lead'
+
+ def get_interested_action(self, cr, uid, interested, context=None):
+ try:
+ model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'crm_lead_channel_interested_act')
+ except ValueError:
+ raise osv.except_osv(_('Error!'), _("The CRM Channel Interested Action is missing"))
+ action = self.pool[model].read(cr, uid, action_id, context=context)
+ action_context = eval(action['context'])
+ action_context['interested'] = interested
+ action['context'] = str(action_context)
+ return action
+
+ def case_interested(self, cr, uid, ids, context=None):
+ return self.get_interested_action(cr, uid, True, context=context)
+
+ def case_disinterested(self, cr, uid, ids, context=None):
+ return self.get_interested_action(cr, uid, False, context=context)
diff --git a/addons/crm_partner_assign/crm_lead_view.xml b/addons/crm_partner_assign/crm_lead_view.xml
index 0d2837d6ca5..5c14680ee78 100644
--- a/addons/crm_partner_assign/crm_lead_view.xml
+++ b/addons/crm_partner_assign/crm_lead_view.xml
@@ -8,27 +8,33 @@
-
+
-
-
-
+
+
+
-% if ctx["history_mode"] in ('whole'):
- % for message in object.message_ids:
- ---- Original Message (${message.date or ''}) ----
- ${message.body | safe}
- % endfor
+
We have been contacted by those prospects that are in your region. Thus, the following leads have been assigned to ${ctx['partner_id'].name}:
+
+
+% for lead in ctx['partner_leads']:
+
${lead.lead_id.name or 'Subject Undefined'}, ${lead.lead_id.contact_name or 'Contact Name Undefined'}, ${lead.lead_id.country_id and lead.lead_id.country_id.name or 'Country Undefined' }, ${lead.lead_id.email_from or 'Email Undefined'}, ${lead.lead_id.phone or ''}
+% endfor
+
+
+% if ctx.get('partner_in_portal'):
+
Please connect to your Partner Portal to get details. On each lead are two buttons on the top left corner that you should press after having contacted the lead: "I'm interested" & "I'm not interested".
+% else:
+
+ You do not have yet a portal access to our database. Please contact
+ ${ctx['partner_id'].user_id and ctx['partner_id'].user_id.email and 'your account manager %s (%s)' % (ctx['partner_id'].user_id.name,ctx['partner_id'].user_id.email) or 'us'}.
+
% endif
-% if ctx['history_mode'] == 'latest':
- ---- Original Message (${object.message_ids[0].date or ''}) ----
- ${object.message_ids[0].body | safe}
+
The lead will be sent to another partner if you do not contact the lead before 20 days.
+
+
Thanks,
+
+
+${ctx['partner_id'].user_id and ctx['partner_id'].user_id.signature or ''}
+
+ Higher is the value, higher is the probability for this partner to get more leads.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm_partner_assign/security/ir.model.access.csv b/addons/crm_partner_assign/security/ir.model.access.csv
index 69b74ef6b3d..81d74bf43e3 100644
--- a/addons/crm_partner_assign/security/ir.model.access.csv
+++ b/addons/crm_partner_assign/security/ir.model.access.csv
@@ -5,3 +5,4 @@ access_crm_partner_report,crm.partner.report.assign.all,model_crm_partner_report
access_res_partner_grade,res.partner.grade,model_res_partner_grade,base.group_sale_salesman,1,1,1,0
access_res_partner_grade_manager,res.partner.grade.manager,model_res_partner_grade,base.group_sale_manager,1,1,1,1
"access_partner_activation_manager","res.partner.activation.manager","model_res_partner_activation","base.group_partner_manager",1,1,1,1
+partner_access_crm_lead,crm.lead,model_crm_lead,portal.group_portal,1,1,0,0
\ No newline at end of file
diff --git a/addons/crm_partner_assign/static/src/js/next.js b/addons/crm_partner_assign/static/src/js/next.js
new file mode 100644
index 00000000000..c40f104d6c6
--- /dev/null
+++ b/addons/crm_partner_assign/static/src/js/next.js
@@ -0,0 +1,13 @@
+openerp.crm_partner_assign = function (instance) {
+ instance.crm_partner_assign = instance.crm_partner_assign || {};
+ instance.crm_partner_assign.next_or_list = function(parent) {
+ var form = parent.inner_widget.views.form.controller;
+ form.dataset.remove_ids([form.dataset.ids[form.dataset.index]]);
+ form.reload();
+ if (!form.dataset.ids.length){
+ parent.inner_widget.switch_mode('list');
+ }
+ parent.do_action({ type: 'ir.actions.act_window_close' });
+ };
+ instance.web.client_actions.add("next_or_list", "instance.crm_partner_assign.next_or_list");
+}
\ No newline at end of file
diff --git a/addons/crm_partner_assign/wizard/__init__.py b/addons/crm_partner_assign/wizard/__init__.py
index 9224173145b..ab6c7b7f06a 100644
--- a/addons/crm_partner_assign/wizard/__init__.py
+++ b/addons/crm_partner_assign/wizard/__init__.py
@@ -20,3 +20,4 @@
##############################################################################
import crm_forward_to_partner
+import crm_channel_interested
\ No newline at end of file
diff --git a/addons/crm_partner_assign/wizard/crm_channel_interested.py b/addons/crm_partner_assign/wizard/crm_channel_interested.py
new file mode 100644
index 00000000000..57db36cb51f
--- /dev/null
+++ b/addons/crm_partner_assign/wizard/crm_channel_interested.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL (). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+from openerp import SUPERUSER_ID
+
+
+class crm_lead_forward_to_partner(osv.TransientModel):
+ """ Forward info history to partners. """
+ _name = 'crm.lead.channel.interested'
+ _columns = {
+ 'interested': fields.boolean('Interested by this lead'),
+ 'contacted': fields.boolean('Did you contact the lead?', help="The lead has been contacted"),
+ 'comment': fields.text('Comment', help="What are the elements that have led to this decision?", required=True),
+ }
+ _defaults = {
+ 'interested': lambda self, cr, uid, c: c.get('interested', True),
+ 'contacted': False,
+ }
+
+ def action_confirm(self, cr, uid, ids, context=None):
+ wizard = self.browse(cr, uid, ids[0], context=context)
+ if wizard.interested and not wizard.contacted:
+ raise osv.except_osv(_('Error!'), _("You must contact the lead before saying that you are interested"))
+ lead_obj = self.pool.get('crm.lead')
+ lead_obj.check_access_rights(cr, uid, 'write')
+ if wizard.interested:
+ message = _('
' % wizard.comment
+ lead_obj.message_post(cr, uid, context.get('active_ids'), body=message, context=context)
+ if values:
+ lead_obj.write(cr, SUPERUSER_ID, context.get('active_ids'), values)
+ if wizard.interested:
+ for lead in lead_obj.browse(cr, uid, context.get('active_ids'), context=context):
+ lead_obj.convert_opportunity(cr, SUPERUSER_ID, [lead.id], lead.partner_id and lead.partner_id.id or None, context=None)
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'next_or_list',
+ 'params': {
+ },
+ }
diff --git a/addons/crm_partner_assign/wizard/crm_channel_interested_view.xml b/addons/crm_partner_assign/wizard/crm_channel_interested_view.xml
new file mode 100644
index 00000000000..400e02cd48a
--- /dev/null
+++ b/addons/crm_partner_assign/wizard/crm_channel_interested_view.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ crm_lead_channel_interested
+ crm.lead.channel.interested
+
+
+
+
+
+ Lead Feedback
+ crm.lead.channel.interested
+ form
+ form
+
+ new
+
+
+
\ No newline at end of file
diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
index 91d462de015..80fa2f28b04 100644
--- a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
+++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
@@ -27,98 +27,182 @@ from openerp.tools.translate import _
class crm_lead_forward_to_partner(osv.TransientModel):
""" Forward info history to partners. """
_name = 'crm.lead.forward.to.partner'
- _inherit = "mail.compose.message"
- def _get_composition_mode_selection(self, cr, uid, context=None):
- composition_mode = super(crm_lead_forward_to_partner, self)._get_composition_mode_selection(cr, uid, context=context)
- composition_mode.append(('forward', 'Forward'))
- return composition_mode
-
- _columns = {
- 'partner_ids': fields.many2many('res.partner',
- 'lead_forward_to_partner_res_partner_rel',
- 'wizard_id', 'partner_id', 'Additional contacts'),
- 'attachment_ids': fields.many2many('ir.attachment',
- 'lead_forward_to_partner_attachment_rel',
- 'wizard_id', 'attachment_id', 'Attachments'),
- 'history_mode': fields.selection([('info', 'Internal notes'),
- ('latest', 'Latest email'), ('whole', 'Whole Story')],
- 'Send history', required=True),
- }
-
- _defaults = {
- 'history_mode': 'info',
- }
+ def _convert_to_assignation_line(self, cr, uid, lead, partner, context=None):
+ lead_location = []
+ partner_location = []
+ if lead.country_id:
+ lead_location.append(lead.country_id.name)
+ if lead.city:
+ lead_location.append(lead.city)
+ if partner:
+ if partner.country_id:
+ partner_location.append(partner.country_id.name)
+ if partner.city:
+ partner_location.append(partner.city)
+ return {'lead_id': lead.id,
+ 'lead_location': ", ".join(lead_location),
+ 'partner_assigned_id': partner and partner.id or False,
+ 'partner_location': ", ".join(partner_location),
+ 'lead_link': self.get_lead_portal_url(cr, uid, lead.id, lead.type, context=context),
+ }
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
- # set as comment, perform overrided document-like action that calls get_record_data
- old_mode = context.get('default_composition_mode', 'forward')
- context['default_composition_mode'] = 'comment'
+ lead_obj = self.pool.get('crm.lead')
+ email_template_obj = self.pool.get('email.template')
+ try:
+ template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'email_template_lead_forward_mail')[1]
+ except ValueError:
+ template_id = False
res = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
- # back to forward mode
- context['default_composition_mode'] = old_mode
- res['composition_mode'] = context['default_composition_mode']
+ active_ids = context.get('active_ids')
+ default_composition_mode = context.get('default_composition_mode')
+ res['assignation_lines'] = []
+ if template_id:
+ res['body'] = email_template_obj.get_email_template(cr, uid, template_id).body_html
+ if active_ids:
+ lead_ids = lead_obj.browse(cr, uid, active_ids, context=context)
+ if default_composition_mode == 'mass_mail':
+ partner_assigned_ids = lead_obj.search_geo_partner(cr, uid, active_ids, context=context)
+ else:
+ partner_assigned_ids = dict((lead.id, lead.partner_assigned_id and lead.partner_assigned_id.id or False) for lead in lead_ids)
+ res['partner_id'] = lead_ids[0].partner_assigned_id.id
+ for lead in lead_ids:
+ partner_id = partner_assigned_ids.get(lead.id) or False
+ partner = False
+ if partner_id:
+ partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
+ res['assignation_lines'].append(self._convert_to_assignation_line(cr, uid, lead, partner))
return res
- def get_record_data(self, cr, uid, model, res_id, context=None):
- """ Override of mail.compose.message, to add default values coming
- form the related lead.
- """
- if context is None:
- context = {}
- res = super(crm_lead_forward_to_partner, self).get_record_data(cr, uid, model, res_id, context=context)
- if model not in ('crm.lead') or not res_id:
- return res
- template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'crm_partner_assign_email_template')[1]
- context['history_mode'] = context.get('history_mode','whole')
- mail_body_fields = ['partner_id', 'partner_name', 'title', 'function', 'street', 'street2', 'zip', 'city', 'country_id', 'state_id', 'email_from', 'phone', 'fax', 'mobile', 'description']
- lead = self.pool.get('crm.lead').browse(cr, uid, res_id, context=context)
- context['mail_body'] = self.pool.get('crm.lead')._mail_body(cr, uid, lead, mail_body_fields, context=context)
- template = self.generate_email_for_composer(cr, uid, template_id, res_id, context)
- res['subject'] = template['subject']
- res['body'] = template['body']
- return res
-
- def on_change_history_mode(self, cr, uid, ids, history_mode, model, res_id, context=None):
- """ Update body when changing history_mode """
- if context is None:
- context = {}
- if model and model == 'crm.lead' and res_id:
- lead = self.pool[model].browse(cr, uid, res_id, context=context)
- context['history_mode'] = history_mode
- body = self.get_record_data(cr, uid, 'crm.lead', res_id, context=context)['body']
- return {'value': {'body': body}}
-
- def create(self, cr, uid, values, context=None):
- """ TDE-HACK: remove 'type' from context, because when viewing an
- opportunity form view, a default_type is set and propagated
- to the wizard, that has a not matching type field. """
- default_type = context.pop('default_type', None)
- new_id = super(crm_lead_forward_to_partner, self).create(cr, uid, values, context=context)
- if default_type:
- context['default_type'] = default_type
- return new_id
-
def action_forward(self, cr, uid, ids, context=None):
- """ Forward the lead to a partner """
- if context is None:
+ lead_obj = self.pool.get('crm.lead')
+ record = self.browse(cr, uid, ids[0], context=context)
+ email_template_obj = self.pool.get('email.template')
+ try:
+ template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'email_template_lead_forward_mail')[1]
+ except ValueError:
+ raise osv.except_osv(_('Email Template Error'),
+ _('The Forward Email Template is not in the database'))
+ try:
+ portal_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')[1]
+ except ValueError:
+ raise osv.except_osv(_('Portal Group Error'),
+ _('The Portal group cannot be found'))
+
+ local_context = context.copy()
+ if not (record.forward_type == 'single'):
+ no_email = set()
+ for lead in record.assignation_lines:
+ if lead.partner_assigned_id and not lead.partner_assigned_id.email:
+ no_email.add(lead.partner_assigned_id.name)
+ if no_email:
+ raise osv.except_osv(_('Email Error'),
+ ('Set an email address for the partner(s): %s' % ", ".join(no_email)))
+ if record.forward_type == 'single' and not record.partner_id.email:
+ raise osv.except_osv(_('Email Error'),
+ ('Set an email address for the partner %s' % record.partner_id.name))
+
+ partners_leads = {}
+ for lead in record.assignation_lines:
+ partner = record.forward_type == 'single' and record.partner_id or lead.partner_assigned_id
+ lead_details = {
+ 'lead_link': lead.lead_link,
+ 'lead_id': lead.lead_id,
+ }
+ if partner:
+ partner_leads = partners_leads.get(partner.id)
+ if partner_leads:
+ partner_leads['leads'].append(lead_details)
+ else:
+ partners_leads[partner.id] = {'partner': partner, 'leads': [lead_details]}
+ stage_id = False
+ if record.assignation_lines and record.assignation_lines[0].lead_id.type == 'lead':
+ try:
+ stage_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'stage_portal_lead_assigned')[1]
+ except ValueError:
+ pass
+
+ for partner_id, partner_leads in partners_leads.items():
+ in_portal = False
+ for contact in (partner.child_ids or [partner]):
+ if contact.user_ids:
+ in_portal = portal_id in [g.id for g in contact.user_ids[0].groups_id]
+
+ local_context['partner_id'] = partner_leads['partner']
+ local_context['partner_leads'] = partner_leads['leads']
+ local_context['partner_in_portal'] = in_portal
+ email_template_obj.send_mail(cr, uid, template_id, ids[0], context=local_context)
+ lead_ids = [lead['lead_id'].id for lead in partner_leads['leads']]
+ values = {'partner_assigned_id': partner_id, 'user_id': partner_leads['partner'].user_id.id}
+ if stage_id:
+ values['stage_id'] = stage_id
+ lead_obj.write(cr, uid, lead_ids, values)
+ self.pool.get('crm.lead').message_subscribe(cr, uid, lead_ids, [partner_id], context=context)
+ return True
+
+ def get_lead_portal_url(self, cr, uid, lead_id, type, context=None):
+ action = type == 'opportunity' and 'action_portal_opportunities' or 'action_portal_leads'
+ try:
+ action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', action)[1]
+ except ValueError:
+ action_id = False
+ portal_link = "%s/?db=%s#id=%s&action=%s&view_type=form" % (self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url'), cr.dbname, lead_id, action_id)
+ return portal_link
+
+ def get_portal_url(self, cr, uid, ids, context=None):
+ portal_link = "%s/?db=%s" % (self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url'), cr.dbname)
+ return portal_link
+
+ _columns = {
+ 'forward_type': fields.selection([('single', 'a single partner: manual selection of partner'), ('assigned', "several partners: automatic assignation, using GPS coordinates and partner's grades"), ], 'Forward selected leads to'),
+ 'partner_id': fields.many2one('res.partner', 'Forward Leads To'),
+ 'assignation_lines': fields.one2many('crm.lead.assignation', 'forward_id', 'Partner Assignation'),
+ 'body': fields.html('Contents', help='Automatically sanitized HTML contents'),
+ }
+
+ _defaults = {
+ 'forward_type': lambda self, cr, uid, c: c.get('forward_type') or 'single',
+ }
+
+
+class crm_lead_assignation (osv.TransientModel):
+ _name = 'crm.lead.assignation'
+ _columns = {
+ 'forward_id': fields.many2one('crm.lead.forward.to.partner', 'Partner Assignation'),
+ 'lead_id': fields.many2one('crm.lead', 'Lead'),
+ 'lead_location': fields.char('Lead Location', size=128),
+ 'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner'),
+ 'partner_location': fields.char('Partner Location', size=128),
+ 'lead_link': fields.char('Lead Single Links', size=128),
+ }
+
+ def on_change_lead_id(self, cr, uid, ids, lead_id, context=None):
+ if not context:
context = {}
- res = {'type': 'ir.actions.act_window_close'}
- wizard = self.browse(cr, uid, ids[0], context=context)
- if wizard.model not in ('crm.lead'):
- return res
+ if not lead_id:
+ return {'value': {'lead_location': False}}
+ lead = self.pool.get('crm.lead').browse(cr, uid, lead_id, context=context)
+ lead_location = []
+ if lead.country_id:
+ lead_location.append(lead.country_id.name)
+ if lead.city:
+ lead_location.append(lead.city)
+ return {'value': {'lead_location': ", ".join(lead_location)}}
- lead = self.pool[wizard.model]
- lead_ids = wizard.res_id and [wizard.res_id] or []
+ def on_change_partner_assigned_id(self, cr, uid, ids, partner_assigned_id, context=None):
+ if not context:
+ context = {}
+ if not partner_assigned_id:
+ return {'value': {'lead_location': False}}
+ partner = self.pool.get('res.partner').browse(cr, uid, partner_assigned_id, context=context)
+ partner_location = []
+ if partner.country_id:
+ partner_location.append(partner.country_id.name)
+ if partner.city:
+ partner_location.append(partner.city)
+ return {'value': {'partner_location': ", ".join(partner_location)}}
- if wizard.composition_mode == 'mass_mail':
- lead_ids = context and context.get('active_ids', []) or []
- value = self.default_get(cr, uid, ['body', 'email_to', 'email_cc', 'subject', 'history_mode'], context=context)
- self.write(cr, uid, ids, value, context=context)
-
- return self.send_mail(cr, uid, ids, context=context)
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
index 0fda8c8beaa..26ad08f1528 100644
--- a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
+++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
@@ -1,36 +1,38 @@
-
crm_lead_forward_to_partnercrm.lead.forward.to.partner
@@ -45,14 +47,11 @@
new
-
+
diff --git a/addons/crm_profiling/i18n/ru.po b/addons/crm_profiling/i18n/ru.po
index 8cbe1695e82..a7325d894c5 100644
--- a/addons/crm_profiling/i18n/ru.po
+++ b/addons/crm_profiling/i18n/ru.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:05+0000\n"
-"PO-Revision-Date: 2012-05-10 17:51+0000\n"
+"PO-Revision-Date: 2013-05-30 14:05+0000\n"
"Last-Translator: Chertykov Denis \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:32+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-05-31 05:38+0000\n"
+"X-Generator: Launchpad (build 16660)\n"
#. module: crm_profiling
#: view:crm_profiling.questionnaire:0
@@ -151,7 +151,7 @@ msgstr "Используйте правила профилирования"
#. module: crm_profiling
#: constraint:crm.segmentation:0
msgid "Error ! You cannot create recursive profiles."
-msgstr ""
+msgstr "Ошибка ! Нельзя создать рекурсивный профиль."
#. module: crm_profiling
#: field:crm.segmentation,answer_yes:0
@@ -200,7 +200,7 @@ msgstr "Сохранить данные"
#. module: crm_profiling
#: view:open.questionnaire:0
msgid "or"
-msgstr ""
+msgstr "или"
#~ msgid ""
#~ "The Object name must start with x_ and not contain any special character !"
diff --git a/addons/crm_todo/i18n/da.po b/addons/crm_todo/i18n/da.po
new file mode 100644
index 00000000000..1214801638f
--- /dev/null
+++ b/addons/crm_todo/i18n/da.po
@@ -0,0 +1,85 @@
+# Danish 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-06-19 17:34+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Danish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-20 05:17+0000\n"
+"X-Generator: Launchpad (build 16673)\n"
+
+#. module: crm_todo
+#: model:ir.model,name:crm_todo.model_project_task
+msgid "Task"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Timebox"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Lead"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "For cancelling the task"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Next"
+msgstr ""
+
+#. module: crm_todo
+#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
+#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
+msgid "My Tasks"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+#: field:crm.lead,task_ids:0
+msgid "Tasks"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Done"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Cancel"
+msgstr ""
+
+#. module: crm_todo
+#: model:ir.model,name:crm_todo.model_crm_lead
+msgid "Lead/Opportunity"
+msgstr ""
+
+#. module: crm_todo
+#: field:project.task,lead_id:0
+msgid "Lead / Opportunity"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "For changing to done state"
+msgstr ""
+
+#. module: crm_todo
+#: view:crm.lead:0
+msgid "Previous"
+msgstr ""
diff --git a/addons/decimal_precision/i18n/ko.po b/addons/decimal_precision/i18n/ko.po
new file mode 100644
index 00000000000..0b3df57f440
--- /dev/null
+++ b/addons/decimal_precision/i18n/ko.po
@@ -0,0 +1,49 @@
+# Korean 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-06-28 09:31+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Korean \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-30 05:56+0000\n"
+"X-Generator: Launchpad (build 16692)\n"
+
+#. module: decimal_precision
+#: field:decimal.precision,digits:0
+msgid "Digits"
+msgstr "자리수"
+
+#. module: decimal_precision
+#: model:ir.actions.act_window,name:decimal_precision.action_decimal_precision_form
+#: model:ir.ui.menu,name:decimal_precision.menu_decimal_precision_form
+msgid "Decimal Accuracy"
+msgstr "소숫점 정확성"
+
+#. module: decimal_precision
+#: field:decimal.precision,name:0
+msgid "Usage"
+msgstr "사용량"
+
+#. module: decimal_precision
+#: sql_constraint:decimal.precision:0
+msgid "Only one value can be defined for each given usage!"
+msgstr ""
+
+#. module: decimal_precision
+#: view:decimal.precision:0
+msgid "Decimal Precision"
+msgstr "소수점 정확성"
+
+#. module: decimal_precision
+#: model:ir.model,name:decimal_precision.model_decimal_precision
+msgid "decimal.precision"
+msgstr "decimal.precision"
diff --git a/addons/delivery/partner.py b/addons/delivery/partner.py
index 477315dfc9b..226b5e493ab 100644
--- a/addons/delivery/partner.py
+++ b/addons/delivery/partner.py
@@ -25,11 +25,9 @@ class res_partner(osv.osv):
_inherit = 'res.partner'
_columns = {
'property_delivery_carrier': fields.property(
- 'delivery.carrier',
type='many2one',
relation='delivery.carrier',
string="Delivery Method",
- view_load=True,
help="This delivery method will be used when invoicing from picking."),
}
diff --git a/addons/delivery/sale.py b/addons/delivery/sale.py
index 86a518ebca9..1b797290632 100644
--- a/addons/delivery/sale.py
+++ b/addons/delivery/sale.py
@@ -51,10 +51,10 @@ class sale_order(osv.osv):
for order in self.browse(cr, uid, ids, context=context):
grid_id = carrier_obj.grid_get(cr, uid, [order.carrier_id.id], order.partner_shipping_id.id)
if not grid_id:
- raise osv.except_osv(_('No grid available !'), _('No grid matching for this carrier !'))
+ raise osv.except_osv(_('No Grid Available!'), _('No grid matching for this carrier!'))
if not order.state in ('draft'):
- raise osv.except_osv(_('Order not in draft state !'), _('The order state have to be draft to add delivery lines.'))
+ raise osv.except_osv(_('Order not in Draft State!'), _('The order state have to be draft to add delivery lines.'))
grid = grid_obj.browse(cr, uid, grid_id, context=context)
diff --git a/addons/document/odt2txt.py b/addons/document/odt2txt.py
old mode 100644
new mode 100755
diff --git a/addons/document_page/document_page.py b/addons/document_page/document_page.py
index f74cfe02a21..7f885018001 100644
--- a/addons/document_page/document_page.py
+++ b/addons/document_page/document_page.py
@@ -66,7 +66,7 @@ class document_page(osv.osv):
'create_date': fields.datetime("Created on", select=True, readonly=True),
'create_uid': fields.many2one('res.users', 'Author', select=True, readonly=True),
'write_date': fields.datetime("Modification Date", select=True, readonly=True),
- 'write_uid': fields.many2one('res.users', "Last Contributor", select=True),
+ 'write_uid': fields.many2one('res.users', "Last Contributor", select=True, readonly=True),
}
_defaults = {
'type':'content',
diff --git a/addons/document_page/document_page_view.xml b/addons/document_page/document_page_view.xml
index 08c77647d17..9d02b47d265 100644
--- a/addons/document_page/document_page_view.xml
+++ b/addons/document_page/document_page_view.xml
@@ -26,6 +26,7 @@
+
@@ -87,7 +88,11 @@
tree,form
- Create web pages
+
+
+ Click to create a new web page.
+
+
diff --git a/addons/document_webdav/__openerp__.py b/addons/document_webdav/__openerp__.py
index ec112ec7c38..befb87829ed 100644
--- a/addons/document_webdav/__openerp__.py
+++ b/addons/document_webdav/__openerp__.py
@@ -24,7 +24,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/addons/document_webdav/test_davclient.py b/addons/document_webdav/test_davclient.py
index 058dc1c748d..f3a8b35b582 100644
--- a/addons/document_webdav/test_davclient.py
+++ b/addons/document_webdav/test_davclient.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#
# Copyright P. Christeas 2008,2009
@@ -24,7 +23,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
""" A trivial HTTP/WebDAV client, used for testing the server
diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py
index f67de272e29..e495f5c9f2f 100644
--- a/addons/document_webdav/webdav_server.py
+++ b/addons/document_webdav/webdav_server.py
@@ -30,7 +30,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
diff --git a/addons/document_webdav/webdav_setup.xml b/addons/document_webdav/webdav_setup.xml
index d75c416a93e..dbf6bc8fbcc 100644
--- a/addons/document_webdav/webdav_setup.xml
+++ b/addons/document_webdav/webdav_setup.xml
@@ -1,4 +1,3 @@
-
+ on_change="onchange_template_id(template_id, composition_mode, model, res_id, context)" domain="[('model_id.model','=',model)]"/>
+
@@ -100,19 +102,13 @@
-
-
+
+
-
-
-
-
-
-
+
+
-
-
-
+
diff --git a/addons/event/res_partner.py b/addons/event/res_partner.py
index fc4afa56e69..b51e1fbb9d3 100644
--- a/addons/event/res_partner.py
+++ b/addons/event/res_partner.py
@@ -21,15 +21,13 @@
from openerp.osv import fields, osv
+
class res_partner(osv.osv):
_inherit = 'res.partner'
_columns = {
'speaker': fields.boolean('Speaker', help="Check this box if this contact is a speaker."),
- 'event_ids': fields.one2many('event.event','main_speaker_id', readonly=True),
- 'event_registration_ids': fields.one2many('event.registration','partner_id', readonly=True),
}
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/event/res_partner_view.xml b/addons/event/res_partner_view.xml
index c3e8073a7ae..7e97f80e30d 100644
--- a/addons/event/res_partner_view.xml
+++ b/addons/event/res_partner_view.xml
@@ -2,9 +2,8 @@
-
-
-
+
+ res.partner.event.info.inheritres.partner
@@ -12,34 +11,8 @@
-
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/addons/event/security/event_security.xml b/addons/event/security/event_security.xml
index 83039ca4686..90a232731a7 100644
--- a/addons/event/security/event_security.xml
+++ b/addons/event/security/event_security.xml
@@ -25,25 +25,35 @@
-
- Event multi-company
+
+ Event: multi-company
- ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
+ ['|',
+ ('company_id', '=', False),
+ ('company_id', 'child_of', [user.company_id.id]),
+ ]
+
-
-
- Event Registration multi-company
+
+ Event/Registration: multi-company
- ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
+ ['|',
+ ('company_id', '=', False),
+ ('company_id', 'child_of', [user.company_id.id]),
+ ]
+
-
-
- Report Event Registration multi-company
+
+ Event/Report Registration: multi-company
- ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
+ ['|',
+ ('company_id', '=', False),
+ ('company_id', 'child_of', [user.company_id.id]),
+ ]
+
diff --git a/addons/event/static/src/img/icon.png b/addons/event/static/description/icon.png
similarity index 100%
rename from addons/event/static/src/img/icon.png
rename to addons/event/static/description/icon.png
diff --git a/addons/event_sale/event_sale.py b/addons/event_sale/event_sale.py
index ec583a58cbf..8bacd37fc15 100644
--- a/addons/event_sale/event_sale.py
+++ b/addons/event_sale/event_sale.py
@@ -70,6 +70,8 @@ class sale_order_line(osv.osv):
'''
create registration with sales order
'''
+ if context is None:
+ context = {}
registration_obj = self.pool.get('event.registration')
sale_obj = self.pool.get('sale.order')
for order_line in self.browse(cr, uid, ids, context=context):
@@ -83,7 +85,8 @@ class sale_order_line(osv.osv):
'origin': order_line.order_id.name,
'event_id': order_line.event_id.id,
}
+ message = _("The registration has been created for event %s from the Sale Order %s. ") % (order_line.event_id.name, order_line.order_id.name)
+ context.update({'mail_create_nolog': True})
registration_id = registration_obj.create(cr, uid, dic, context=context)
- message = _("The registration %s has been created from the Sales Order %s.") % (registration_id, order_line.order_id.name)
registration_obj.message_post(cr, uid, [registration_id], body=message, context=context)
return super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)
diff --git a/addons/event_sale/i18n/da.po b/addons/event_sale/i18n/da.po
new file mode 100644
index 00000000000..fb3faa70fc0
--- /dev/null
+++ b/addons/event_sale/i18n/da.po
@@ -0,0 +1,90 @@
+# Danish 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-06-19 17:36+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Danish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-06-20 05:17+0000\n"
+"X-Generator: Launchpad (build 16673)\n"
+
+#. module: event_sale
+#: model:ir.model,name:event_sale.model_product_product
+msgid "Product"
+msgstr ""
+
+#. module: event_sale
+#: help:product.product,event_ok:0
+msgid ""
+"Determine if a product needs to create automatically an event registration "
+"at the confirmation of a sales order line."
+msgstr ""
+
+#. module: event_sale
+#: help:sale.order.line,event_id:0
+msgid ""
+"Choose an event and it will automatically create a registration for this "
+"event."
+msgstr ""
+
+#. module: event_sale
+#: model:event.event,name:event_sale.event_technical_training
+msgid "Technical training in Grand-Rosiere"
+msgstr ""
+
+#. module: event_sale
+#: help:product.product,event_type_id:0
+msgid ""
+"Select event types so when we use this product in sales order lines, it will "
+"filter events of this type only."
+msgstr ""
+
+#. module: event_sale
+#: field:product.product,event_type_id:0
+msgid "Type of Event"
+msgstr ""
+
+#. module: event_sale
+#: field:sale.order.line,event_ok:0
+msgid "event_ok"
+msgstr ""
+
+#. module: event_sale
+#: field:product.product,event_ok:0
+msgid "Event Subscription"
+msgstr ""
+
+#. module: event_sale
+#: field:sale.order.line,event_type_id:0
+msgid "Event Type"
+msgstr ""
+
+#. module: event_sale
+#: model:product.template,name:event_sale.event_product_product_template
+msgid "Technical Training"
+msgstr ""
+
+#. module: event_sale
+#: code:addons/event_sale/event_sale.py:88
+#, python-format
+msgid "The registration %s has been created from the Sales Order %s."
+msgstr ""
+
+#. module: event_sale
+#: field:sale.order.line,event_id:0
+msgid "Event"
+msgstr ""
+
+#. module: event_sale
+#: model:ir.model,name:event_sale.model_sale_order_line
+msgid "Sales Order Line"
+msgstr ""
diff --git a/addons/fetchmail/fetchmail_view.xml b/addons/fetchmail/fetchmail_view.xml
index 4e653adce28..5ee17c61b6f 100644
--- a/addons/fetchmail/fetchmail_view.xml
+++ b/addons/fetchmail/fetchmail_view.xml
@@ -97,15 +97,17 @@
General Settingsbase.config.settings
-
-
-