diff --git a/addons/account/account_financial_report.py b/addons/account/account_financial_report.py
index 28b5e08dc99..1d9a4a794eb 100644
--- a/addons/account/account_financial_report.py
+++ b/addons/account/account_financial_report.py
@@ -39,6 +39,8 @@ class account_financial_report(osv.osv):
_description = "Account Report"
def _get_level(self, cr, uid, ids, field_name, arg, context=None):
+ '''Returns a dictionary with key=the ID of a record and value = the level of this
+ record in the tree structure.'''
res = {}
for report in self.browse(cr, uid, ids, context=context):
level = 0
@@ -48,6 +50,8 @@ class account_financial_report(osv.osv):
return res
def _get_children_by_order(self, cr, uid, ids, context=None):
+ '''returns a dictionary with the key= the ID of a record and value = all its children,
+ computed recursively, and sorted by sequence. Ready for the printing'''
res = []
for id in ids:
res.append(id)
@@ -56,6 +60,12 @@ class account_financial_report(osv.osv):
return res
def _get_balance(self, cr, uid, ids, field_names, args, context=None):
+ '''returns a dictionary with key=the ID of a record and value=the balance amount
+ computed for this record. If the record is of type :
+ 'accounts' : it's the sum of the linked accounts
+ 'account_type' : it's the sum of leaf accoutns with such an account_type
+ 'account_report' : it's the amount of the related report
+ 'sum' : it's the sum of the children of this record (aka a 'view' record)'''
account_obj = self.pool.get('account.account')
res = {}
for report in self.browse(cr, uid, ids, context=context):
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index d7b2052305b..e07a003c981 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -1390,7 +1390,12 @@ class account_invoice_line(osv.osv):
# XXX this gets the default account for the user's company,
# it should get the default account for the invoice's company
# however, the invoice's company does not reach this point
- prop = self.pool.get('ir.property').get(cr, uid, 'property_account_income_categ', 'product.category', context=context)
+ if context is None:
+ context = {}
+ if context.get('type') in ('out_invoice','out_refund'):
+ prop = self.pool.get('ir.property').get(cr, uid, 'property_account_income_categ', 'product.category', context=context)
+ else:
+ prop = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category', context=context)
return prop and prop.id or False
_defaults = {
diff --git a/addons/account/res_config.py b/addons/account/res_config.py
index 72d30c11cfd..53c604161ea 100644
--- a/addons/account/res_config.py
+++ b/addons/account/res_config.py
@@ -151,12 +151,12 @@ class account_config_settings(osv.osv_memory):
self.write(cr, uid, [id], vals, context)
return id
- def onchange_company_id(self, cr, uid, ids, company_id):
+ def onchange_company_id(self, cr, uid, ids, company_id, context=None):
# update related fields
values = {}
values['currency_id'] = False
if company_id:
- company = self.pool.get('res.company').browse(cr, uid, company_id)
+ company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
has_chart_of_accounts = company_id not in self.pool.get('account.installer').get_unconfigured_cmp(cr, uid)
fiscalyear_count = self.pool.get('account.fiscalyear').search_count(cr, uid,
[('date_start', '<=', time.strftime('%Y-%m-%d')), ('date_stop', '>=', time.strftime('%Y-%m-%d')),
diff --git a/addons/account/res_config_view.xml b/addons/account/res_config_view.xml
index 4bfd3697d89..7977c0fc505 100644
--- a/addons/account/res_config_view.xml
+++ b/addons/account/res_config_view.xml
@@ -33,7 +33,7 @@
diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py
index b7330352b12..b335063b758 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -331,6 +331,9 @@ class account_asset_asset(osv.osv):
depreciation_obj = self.pool.get('account.asset.depreciation.line')
period = period_obj.browse(cr, uid, period_id, context=context)
depreciation_ids = depreciation_obj.search(cr, uid, [('asset_id', 'in', ids), ('depreciation_date', '<=', period.date_stop), ('depreciation_date', '>=', period.date_start), ('move_check', '=', False)], context=context)
+ if context is None:
+ context = {}
+ context.update({'depreciation_date':period.date_stop})
return depreciation_obj.create_move(cr, uid, depreciation_ids, context=context)
def create(self, cr, uid, vals, context=None):
@@ -388,7 +391,7 @@ class account_asset_depreciation_line(osv.osv):
created_move_ids = []
asset_ids = []
for line in self.browse(cr, uid, ids, context=context):
- depreciation_date = time.strftime('%Y-%m-%d')
+ depreciation_date = context.get('depreciation_date') or time.strftime('%Y-%m-%d')
period_ids = period_obj.find(cr, uid, depreciation_date, context=context)
company_currency = line.asset_id.company_id.currency_id.id
current_currency = line.asset_id.currency_id.id
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index 285a3529ee7..aeee35c93dc 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -238,7 +238,12 @@ class res_partner(osv.osv):
from report import account_followup_print
assert len(ids) == 1
+ if context is None:
+ context = {}
partner = self.browse(cr, uid, ids[0], context=context)
+ #copy the context to not change global context. Overwrite it because _() looks for the lang in local variable 'context'.
+ #Set the language to use = the partner language
+ context = dict(context, lang=partner.lang)
followup_table = ''
if partner.unreconciled_aml_ids:
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
@@ -251,13 +256,14 @@ class res_partner(osv.osv):
followup_table += '''
- Invoice date
- Reference
- Due date
- Amount (%s)
- Lit.
+ ''' + _("Invoice Date") + '''
+ ''' + _("Description") + '''
+ ''' + _("Reference") + '''
+ ''' + _("Due Date") + '''
+ ''' + _("Amount") + " (%s)" % (currency.symbol) + '''
+ ''' + _("Lit.") + '''
- ''' % (currency.symbol)
+ '''
total = 0
for aml in currency_dict['line']:
block = aml['blocked'] and 'X' or ' '
@@ -268,13 +274,28 @@ class res_partner(osv.osv):
if date <= current_date and aml['balance'] > 0:
strbegin = ""
strend = " "
- followup_table +="" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + " "
+ followup_table +="" + strbegin + str(aml['date']) + strend + strbegin + aml['name'] + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + " "
total = rml_parse.formatLang(total, dp='Account', currency_obj=currency)
followup_table += '''
-
Amount due: %s ''' % (total)
+
''' + _("Amount due") + ''' : %s ''' % (total)
return followup_table
+ def write(self, cr, uid, ids, vals, context=None):
+ if vals.get("payment_responsible_id", False):
+ for part in self.browse(cr, uid, ids, context=context):
+ if part.payment_responsible_id <> vals["payment_responsible_id"]:
+ #Find partner_id of user put as responsible
+ responsible_partner_id = self.pool.get("res.users").browse(cr, uid, vals['payment_responsible_id'], context=context).partner_id.id
+ self.pool.get("mail.thread").message_post(cr, uid, 0,
+ body = _("You became responsible to do the next action for the payment follow-up of") + "
" + part.name + " ",
+ type = 'comment',
+ subtype = "mail.mt_comment", context = context,
+ model = 'res.partner', res_id = part.id,
+ notified_partner_ids = [(6, 0, [responsible_partner_id])],
+ partner_ids = [(6, 0, [responsible_partner_id])])
+ return super(res_partner, self).write(cr, uid, ids, vals, context=context)
+
def action_done(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'payment_next_action_date': False, 'payment_next_action':'', 'payment_responsible_id': False}, context=context)
@@ -408,13 +429,16 @@ class res_partner(osv.osv):
_inherit = "res.partner"
_columns = {
'payment_responsible_id':fields.many2one('res.users', ondelete='set null', string='Follow-up Responsible',
- help="Optionally you can assign a user to this field, which will make him responsible for the action."),
- 'payment_note':fields.text('Customer Payment Promise', help="Payment Note"),
+ help="Optionally you can assign a user to this field, which will make him responsible for the action.",
+ track_visibility="onchange"),
+ 'payment_note':fields.text('Customer Payment Promise', help="Payment Note", track_visibility="onchange"),
'payment_next_action':fields.text('Next Action',
- help="This is the next action to be taken. It will automatically be set when the partner gets a follow-up level that requires a manual action. "),
+ help="This is the next action to be taken. It will automatically be set when the partner gets a follow-up level that requires a manual action. ",
+ track_visibility="onchange"),
'payment_next_action_date':fields.date('Next Action Date',
help="This is when the manual follow-up is needed. " \
- "The date will be set to the current date when the partner gets a follow-up level that requires a manual action. Can be practical to set manually e.g. to see if he keeps his promises."),
+ "The date will be set to the current date when the partner gets a follow-up level that requires a manual action. "\
+ "Can be practical to set manually e.g. to see if he keeps his promises."),
'unreconciled_aml_ids':fields.one2many('account.move.line', 'partner_id', domain=['&', ('reconcile_id', '=', False), '&',
('account_id.active','=', True), '&', ('account_id.type', '=', 'receivable'), ('state', '!=', 'draft')]),
'latest_followup_date':fields.function(_get_latest, method=True, type='date', string="Latest Follow-up Date",
diff --git a/addons/account_followup/account_followup_customers.xml b/addons/account_followup/account_followup_customers.xml
index 8a27730b003..691d1555e8d 100644
--- a/addons/account_followup/account_followup_customers.xml
+++ b/addons/account_followup/account_followup_customers.xml
@@ -35,10 +35,10 @@
-
+
-
+
@@ -132,6 +132,18 @@
-
+
+ My Follow-Ups
+
+ res.partner
+ form
+ tree,form
+ [('payment_amount_due', '>', 0.0)]
+ {'Followupfirst':True, 'search_default_todo': True, 'search_default_my': True}
+
+
+
+
diff --git a/addons/account_followup/wizard/account_followup_print.py b/addons/account_followup/wizard/account_followup_print.py
index e93b4dd8b69..76aee365e00 100644
--- a/addons/account_followup/wizard/account_followup_print.py
+++ b/addons/account_followup/wizard/account_followup_print.py
@@ -26,6 +26,8 @@ from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.translate import _
+from openerp import SUPERUSER_ID
+
class account_followup_stat_by_partner(osv.osv):
_name = "account_followup.stat.by.partner"
_description = "Follow-up Statistics by Partner"
@@ -127,7 +129,7 @@ class account_followup_print(osv.osv_memory):
'email_body': fields.text('Email Body'),
'summary': fields.text('Summary', readonly=True),
'test_print': fields.boolean('Test Print',
- help='Check if you want to print follow-ups without changing follow-ups level.'),
+ help='Check if you want to print follow-ups without changing follow-up level.'),
}
def _get_followup(self, cr, uid, context=None):
@@ -204,7 +206,7 @@ class account_followup_print(osv.osv_memory):
if not part.unreconciled_aml_ids:
partners_to_clear.append(part.id)
self.pool.get('res.partner').action_done(cr, uid, partners_to_clear, context=context)
- return len(ids)
+ return len(partners_to_clear)
def do_process(self, cr, uid, ids, context=None):
if context is None:
@@ -313,6 +315,13 @@ class account_followup_print(osv.osv_memory):
if stat_line_id not in partner_list:
partner_list.append(stat_line_id)
to_update[str(id)]= {'level': fups[followup_line_id][1], 'partner_id': stat_line_id}
+ #Remove partners that are other companies in OpenERP
+ comp_obj = self.pool.get("res.company")
+ comp_ids = comp_obj.search(cr, SUPERUSER_ID, [], context=context)
+ for comp in comp_obj.browse(cr, SUPERUSER_ID, comp_ids, context=context):
+ company_partner_wiz_id = comp.partner_id.id * 10000 + company_id
+ if company_partner_wiz_id in partner_list:
+ partner_list.remove(company_partner_wiz_id)
return {'partner_ids': partner_list, 'to_update': to_update}
account_followup_print()
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index 45edba33d34..c6f754ed18f 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -49,13 +49,25 @@ class account_config_settings(osv.osv_memory):
'company_id', 'income_currency_exchange_account_id',
type='many2one',
relation='account.account',
- string="Gain Exchange Rate Account"),
+ string="Gain Exchange Rate Account",
+ domain="[('type', '=', 'other')]"),
'expense_currency_exchange_account_id': fields.related(
'company_id', 'expense_currency_exchange_account_id',
type="many2one",
relation='account.account',
- string="Loss Exchange Rate Account"),
+ string="Loss Exchange Rate Account",
+ domain="[('type', '=', 'other')]"),
}
+ def onchange_company_id(self, cr, uid, ids, company_id, context=None):
+ res = super(account_config_settings, self).onchange_company_id(cr, uid, ids, company_id, context=context)
+ if company_id:
+ company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
+ res['value'].update({'income_currency_exchange_account_id': company.income_currency_exchange_account_id and company.income_currency_exchange_account_id.id or False,
+ 'expense_currency_exchange_account_id': company.expense_currency_exchange_account_id and company.expense_currency_exchange_account_id.id or False})
+ else:
+ res['value'].update({'income_currency_exchange_account_id': False,
+ 'expense_currency_exchange_account_id': False})
+ return res
class account_voucher(osv.osv):
def _check_paid(self, cr, uid, ids, name, args, context=None):
diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml
index 5a204d605d6..b869f6c83b2 100644
--- a/addons/account_voucher/voucher_payment_receipt_view.xml
+++ b/addons/account_voucher/voucher_payment_receipt_view.xml
@@ -307,8 +307,9 @@
+
-
+
-
+
+
+
-
-
+
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index d5f90d8a653..294adc863b5 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -567,7 +567,8 @@ class crm_lead(base_stage, format_address, osv.osv):
for opportunity in opportunities:
subject.append(opportunity.name)
title = "%s : %s" % (opportunity.type == 'opportunity' and _('Merged opportunity') or _('Merged lead'), opportunity.name)
- details.append(self._mail_body(cr, uid, opportunity, CRM_LEAD_FIELDS_TO_MERGE, title=title, context=context))
+ fields = list(CRM_LEAD_FIELDS_TO_MERGE)
+ details.append(self._mail_body(cr, uid, opportunity, fields, title=title, context=context))
# Chatter message's subject
subject = subject[0] + ": " + ", ".join(subject[1:])
@@ -627,7 +628,10 @@ class crm_lead(base_stage, format_address, osv.osv):
opportunities = self.browse(cr, uid, ids, context=context)
sequenced_opps = []
for opportunity in opportunities:
- sequenced_opps.append((opportunity.stage_id and opportunity.stage_id.state != 'cancel' and opportunity.stage_id.sequence or 0, opportunity))
+ if opportunity.stage_id and opportunity.stage_id.state != 'cancel':
+ sequenced_opps.append((opportunity.stage_id.sequence, opportunity))
+ else:
+ sequenced_opps.append((-1, opportunity))
sequenced_opps.sort(key=lambda tup: tup[0], reverse=True)
opportunities = [opportunity for sequence, opportunity in sequenced_opps]
ids = [opportunity.id for opportunity in opportunities]
@@ -636,7 +640,8 @@ class crm_lead(base_stage, format_address, osv.osv):
tail_opportunities = opportunities_rest
- merged_data = self._merge_data(cr, uid, ids, highest, CRM_LEAD_FIELDS_TO_MERGE, context=context)
+ fields = list(CRM_LEAD_FIELDS_TO_MERGE)
+ merged_data = self._merge_data(cr, uid, ids, highest, fields, context=context)
# Merge messages and attachements into the first opportunity
self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context)
@@ -651,7 +656,7 @@ class crm_lead(base_stage, format_address, osv.osv):
section_stages = self.pool.get('crm.case.section').read(cr, uid, merged_data['section_id'], ['stage_ids'], context=context)
if merged_data.get('stage_id') not in section_stages['stage_ids']:
stages_sequences = self.pool.get('crm.case.stage').search(cr, uid, [('id','in',section_stages['stage_ids'])], order='sequence', limit=1, context=context)
- merged_data['stage_id'] = stages_sequences[0]
+ merged_data['stage_id'] = stages_sequences and stages_sequences[0] or False
# Write merged data into first opportunity
self.write(cr, uid, [highest.id], merged_data, context=context)
# Delete tail opportunities
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 3e9249aa6fa..fc43339ba8e 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -327,6 +327,7 @@
+
diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py
index 32396b95f4e..e67b7c0c7be 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity.py
+++ b/addons/crm/wizard/crm_lead_to_opportunity.py
@@ -58,11 +58,11 @@ class crm_lead2opportunity_partner(osv.osv_memory):
if partner_id:
# Search for opportunities that have the same partner and that arent done or cancelled
- ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id)])
+ ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), ('state', '!=', 'done')])
for id in ids:
tomerge.add(id)
if email:
- ids = lead_obj.search(cr, uid, [('email_from', 'ilike', email[0])])
+ ids = lead_obj.search(cr, uid, [('email_from', 'ilike', email[0]), ('state', '!=', 'done')])
for id in ids:
tomerge.add(id)
diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
index 8bfd60fccec..00686de1c8e 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
@@ -21,7 +21,7 @@
-
+
@@ -67,7 +67,7 @@
-
+
diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml
index 1dc98b6b68f..f68abeb8a52 100644
--- a/addons/crm/wizard/crm_merge_opportunities_view.xml
+++ b/addons/crm/wizard/crm_merge_opportunities_view.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/addons/crm_partner_assign/crm_lead_view.xml b/addons/crm_partner_assign/crm_lead_view.xml
index 2cffb6fb899..0d2837d6ca5 100644
--- a/addons/crm_partner_assign/crm_lead_view.xml
+++ b/addons/crm_partner_assign/crm_lead_view.xml
@@ -62,5 +62,66 @@
+
+ crm.lead.lead.geo_assign.inherit
+ crm.lead
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ crm.lead.lead.geo_assign.tree.inherit
+ crm.lead
+
+
+
+
+
+
+
+
+
+ crm.lead.partner.filter.assigned
+ crm.lead
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/edi/controllers/main.py b/addons/edi/controllers/main.py
index 14cd97b3e62..7e27428b63b 100644
--- a/addons/edi/controllers/main.py
+++ b/addons/edi/controllers/main.py
@@ -1,4 +1,5 @@
import simplejson
+import urllib
import openerp.addons.web.http as openerpweb
import openerp.addons.web.controllers.main as webmain
@@ -14,11 +15,15 @@ class EDI(openerpweb.Controller):
modules_json = simplejson.dumps(modules)
js = "\n ".join('' % i for i in webmain.manifest_list(req, modules_str, 'js'))
css = "\n ".join(' ' % i for i in webmain.manifest_list(req, modules_str, 'css'))
+
+ # `url` may contain a full URL with a valid query string, we basically want to watch out for XML brackets and double-quotes
+ safe_url = urllib.quote_plus(url,':/?&;=')
+
return webmain.html_template % {
'js': js,
'css': css,
'modules': modules_json,
- 'init': 's.edi.edi_import("%s");' % url,
+ 'init': 's.edi.edi_import("%s");' % safe_url,
}
@openerpweb.jsonrequest
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index 92465c1b84e..5700a07f519 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -371,7 +371,6 @@ class hr_applicant(base_stage, osv.Model):
update_vals = {}
update_vals.update({
- 'description': msg.get('body'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
})
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index f709a224a45..b6a0bdd4ccf 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -187,6 +187,8 @@
domain="[('date_action','<>',False)]" help="Filter and view on next actions and date"/>
+
+
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 16587ae24fd..77573f0d2f8 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -310,8 +310,8 @@ class mail_message(osv.Model):
partner_tree = dict((partner[0], partner) for partner in partners)
# 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see
- attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname'], context=context)
- attachments_tree = dict((attachment['id'], {'id': attachment['id'], 'filename': attachment['datas_fname']}) for attachment in attachments)
+ attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname', 'name'], context=context)
+ attachments_tree = dict((attachment['id'], {'id': attachment['id'], 'filename': attachment['datas_fname'], 'name': attachment['name']}) for attachment in attachments)
# 3. Update message dictionaries
for message_dict in messages:
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index 9d7237ca907..7a2be4aed01 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -773,7 +773,7 @@ class mail_thread(osv.AbstractModel):
msg_dict['author_id'] = author_ids[0]
else:
msg_dict['email_from'] = message.get('from')
- partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)
+ partner_ids = self._message_find_partners(cr, uid, message, ['To', 'Cc'], context=context)
msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
if 'Date' in message:
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 0b3bddffde1..0872d049162 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -104,8 +104,8 @@ openerp.mail = function (session) {
// returns the file type of a file based on its extension
// As it only looks at the extension it is quite approximative.
filetype: function(url){
- url = url.filename || url;
- var tokens = (url+'').split('.');
+ var url = url && url.filename || url;
+ var tokens = typeof url == 'string' ? url.split('.') : [];
if(tokens.length <= 1){
return 'unknown';
}
diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index edf01290398..299d1494fa6 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -102,7 +102,7 @@ class procurement_order(osv.osv):
readonly=True, required=True, help="If you encode manually a Procurement, you probably want to use" \
" a make to order method."),
'note': fields.text('Note'),
- 'message': fields.char('Latest error', help="Exception occurred while computing procurement orders."),
+ 'message': fields.text('Latest error', help="Exception occurred while computing procurement orders."),
'state': fields.selection([
('draft','Draft'),
('cancel','Cancelled'),
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 4169318e9f6..df12a75a567 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -875,7 +875,7 @@ class sale_order_line(osv.osv):
date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT)
result = {}
- warning_msgs = {}
+ warning_msgs = ''
product_obj = product_obj.browse(cr, uid, product, context=context_partner)
uom2 = False
diff --git a/addons/web_linkedin/web_linkedin.py b/addons/web_linkedin/web_linkedin.py
index 277b4497ffc..62883840f2d 100644
--- a/addons/web_linkedin/web_linkedin.py
+++ b/addons/web_linkedin/web_linkedin.py
@@ -21,6 +21,7 @@
import base64
import urllib2
+from urlparse import urlparse, urlunparse
import openerp
from openerp.osv import fields, osv
@@ -30,11 +31,12 @@ class Binary(openerp.addons.web.http.Controller):
@openerp.addons.web.http.jsonrequest
def url2binary(self, req, url):
- if not url.startswith("http"):
- raise Exception("Not allowed to load a file using this protocol")
- if url.count("?") > 0 or url.count("&") > 0 or url.count("=") > 0:
- raise Exception("Not allowed to use GET parameters")
+ """Used exclusively to load images from LinkedIn profiles, must not be used for anything else."""
req.session.assert_valid(force=True)
+ _scheme, _netloc, path, params, query, fragment = urlparse(url)
+ # media.linkedin.com is the master domain for LinkedIn media (replicated to CDNs),
+ # so forcing it should always work and prevents abusing this method to load arbitrary URLs
+ url = urlunparse(('http', 'media.linkedin.com', path, params, query, fragment))
bfile = urllib2.urlopen(url)
return base64.b64encode(bfile.read())