[MERGE] forward port of branch saas-6 up to a0c64bebe6
This commit is contained in:
@@ -82,8 +82,9 @@ class MailMail(osv.Model):
|
||||
body = tools.append_content_to_html(base, body, plaintext=False, container_tag='div')
|
||||
# resolve relative image url to absolute for outlook.com
|
||||
def _sub_relative2absolute(match):
|
||||
return match.group(1) + urlparse.urljoin(domain, match.group(2)) + '"'
|
||||
body = re.sub('(<img(?=\s)[^>]*\ssrc=")(/[^/][^"]+)"', _sub_relative2absolute, body)
|
||||
return match.group(1) + urlparse.urljoin(domain, match.group(2))
|
||||
body = re.sub('(<img(?=\s)[^>]*\ssrc=")(/[^/][^"]+)', _sub_relative2absolute, body)
|
||||
body = re.sub(r'(<[^>]+\bstyle="[^"]+\burl\(\'?)(/[^/\'][^\'")]+)', _sub_relative2absolute, body)
|
||||
|
||||
# generate tracking URL
|
||||
if mail.statistics_ids:
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
<field name="config_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_categ_id"/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Salesperson" name="User" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Product Category" context="{'group_by':'product_categ_id'}"/>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<field name="product_id"/>
|
||||
<field name="user_id"/>
|
||||
<group expand="0" string="Extended Filters">
|
||||
<field name="categ_id"/>
|
||||
<field name="categ_id" filter_domain="[('categ_id', 'child_of', self)]"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
|
||||
@@ -2783,12 +2783,15 @@ class stock_move(osv.osv):
|
||||
'product_uom_qty': uom_qty,
|
||||
'procure_method': 'make_to_stock',
|
||||
'restrict_lot_id': restrict_lot_id,
|
||||
'restrict_partner_id': restrict_partner_id,
|
||||
'split_from': move.id,
|
||||
'procurement_id': move.procurement_id.id,
|
||||
'move_dest_id': move.move_dest_id.id,
|
||||
'origin_returned_move_id': move.origin_returned_move_id.id,
|
||||
}
|
||||
|
||||
if restrict_partner_id:
|
||||
defaults['restrict_partner_id'] = restrict_partner_id
|
||||
|
||||
if context.get('source_location_id'):
|
||||
defaults['location_id'] = context['source_location_id']
|
||||
new_move = self.copy(cr, uid, move.id, defaults, context=context)
|
||||
|
||||
@@ -182,13 +182,13 @@ class stock_landed_cost(osv.osv):
|
||||
if not cost.valuation_adjustment_lines or not self._check_sum(cr, uid, cost, context=context):
|
||||
raise UserError(_('You cannot validate a landed cost which has no valid valuation adjustments lines. Did you click on Compute?'))
|
||||
move_id = self._create_account_move(cr, uid, cost, context=context)
|
||||
quant_dict = {}
|
||||
for line in cost.valuation_adjustment_lines:
|
||||
if not line.move_id:
|
||||
continue
|
||||
per_unit = line.final_cost / line.quantity
|
||||
diff = per_unit - line.former_cost_per_unit
|
||||
quants = [quant for quant in line.move_id.quant_ids]
|
||||
quant_dict = {}
|
||||
for quant in quants:
|
||||
if quant.id not in quant_dict:
|
||||
quant_dict[quant.id] = quant.cost + diff
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
<group>
|
||||
<field name="split_method"/>
|
||||
<field name="standard_price"/>
|
||||
<field name="property_account_expense_id"/>
|
||||
<field name="property_account_expense_id" domain="[('internal_type','=','other'),('deprecated', '=', False)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
|
||||
@@ -34,7 +34,6 @@ import openerp
|
||||
import openerp.modules.registry
|
||||
from openerp.addons.base.ir.ir_qweb import AssetsBundle, QWebTemplateNotFound
|
||||
from openerp.modules import get_module_resource
|
||||
from openerp.service import model as service_model
|
||||
from openerp.tools import topological_sort
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools import ustr
|
||||
@@ -961,10 +960,7 @@ class DataSet(http.Controller):
|
||||
if method.startswith('_'):
|
||||
raise AccessError(_("Underscore prefixed methods cannot be remotely called"))
|
||||
|
||||
@service_model.check
|
||||
def checked_call(__dbname, *args, **kwargs):
|
||||
return getattr(request.registry.get(model), method)(request.cr, request.uid, *args, **kwargs)
|
||||
return checked_call(request.db, *args, **kwargs)
|
||||
return getattr(request.registry.get(model), method)(request.cr, request.uid, *args, **kwargs)
|
||||
|
||||
@http.route('/web/dataset/call', type='json', auth="user")
|
||||
def call(self, model, method, args, domain_id=None, context_id=None):
|
||||
|
||||
@@ -85,6 +85,8 @@ class sale_quote(http.Controller):
|
||||
return request.website.render('website.404')
|
||||
if order.require_payment:
|
||||
return request.website.render('website.404')
|
||||
if order.state != 'sent':
|
||||
return False
|
||||
attachments=sign and [('signature.png', sign.decode('base64'))] or []
|
||||
order_obj.action_confirm(request.cr, SUPERUSER_ID, [order_id], context=request.context)
|
||||
message = _('Order signed by %s') % (signer,)
|
||||
@@ -97,6 +99,8 @@ class sale_quote(http.Controller):
|
||||
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
if order.state != 'sent':
|
||||
return werkzeug.utils.redirect("/quote/%s/%s?message=4" % (order_id, token))
|
||||
request.registry.get('sale.order').action_cancel(request.cr, SUPERUSER_ID, [order_id])
|
||||
message = post.get('decline_message')
|
||||
if message:
|
||||
|
||||
@@ -62,6 +62,7 @@ if(!$('.o_website_quote').length) {
|
||||
submitForm: function(ev){
|
||||
// extract data
|
||||
var self = this;
|
||||
var $confirm_btn = self.$el.find('button[type="submit"]');
|
||||
var href = self.$el.find('form').attr("action");
|
||||
var action = href.match(/quote\/([a-z]+)/);
|
||||
var order_id = href.match(/order_id=(.*)&/);
|
||||
@@ -84,6 +85,8 @@ if(!$('.o_website_quote').length) {
|
||||
})
|
||||
return false;
|
||||
}
|
||||
$confirm_btn.prepend('<i class="fa fa-spinner fa-spin"></i> ');
|
||||
$confirm_btn.attr('disabled', true);
|
||||
ajax.jsonRpc("/quote/"+action[1], 'call', {
|
||||
'order_id': parseInt(order_id[1]),
|
||||
'token': token,
|
||||
|
||||
@@ -225,6 +225,14 @@
|
||||
Your transaction is waiting confirmation.
|
||||
<span t-if='tx_post_msg' t-raw="tx_post_msg"/>
|
||||
</div>
|
||||
<div class="alert alert-warning alert-dismissable" t-if="message==4 and quotation.state != 'sent'">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
|
||||
This order has already been
|
||||
<t t-if="quotation.state=='cancel'">cancelled</t>
|
||||
<t t-if="quotation.state not in ('cancel','draft')">validated</t>
|
||||
! You can <a href="#discussion">contact us</a> for
|
||||
any question.
|
||||
</div>
|
||||
|
||||
<!-- modal relative to the actions Accept/Reject/Cancel -->
|
||||
<div class="modal fade" id="modalaccept" role="dialog" aria-hidden="true">
|
||||
|
||||
+1
-1
@@ -1973,7 +1973,7 @@ Read-Write Field
|
||||
Read-only fields, which only display content and don't allow the
|
||||
user to modify it can be useful, but most fields in Odoo also allow editing.
|
||||
This makes the field classes more complicated, mostly because fields are
|
||||
supposed to handle both and editable and non-editable mode, those modes are
|
||||
supposed to handle both editable and non-editable mode, those modes are
|
||||
often completely different (for design and usability purpose) and the fields
|
||||
must be able to switch between modes at any moment.
|
||||
|
||||
|
||||
@@ -552,7 +552,7 @@ class view(osv.osv):
|
||||
separator = child.get('separator', ',')
|
||||
if separator == ' ':
|
||||
separator = None # squash spaces
|
||||
to_add = map(str.strip, child.get('add', '').split(separator))
|
||||
to_add = filter(bool, map(str.strip, child.get('add', '').split(separator)))
|
||||
to_remove = map(str.strip, child.get('remove', '').split(separator))
|
||||
values = map(str.strip, node.get(attribute, '').split(separator))
|
||||
value = (separator or ' ').join(filter(lambda s: s not in to_remove, values) + to_add)
|
||||
|
||||
@@ -748,7 +748,7 @@ class test_views(ViewCase):
|
||||
<attribute name="thing">bob tata lolo</attribute>
|
||||
<attribute name="thing" add="bibi and co" remove="tata" separator=" " />
|
||||
<attribute name="otherthing">bob, tata,lolo</attribute>
|
||||
<attribute name="otherthing" add="bibi" remove="tata, bob"/>
|
||||
<attribute name="otherthing" remove="tata, bob"/>
|
||||
</footer>
|
||||
"""
|
||||
})
|
||||
@@ -768,7 +768,7 @@ class test_views(ViewCase):
|
||||
E.p("Replacement data"),
|
||||
E.footer(
|
||||
E.button(name="action_next", type="object", string="New button"),
|
||||
thing="bob lolo bibi and co", otherthing="lolo,bibi"
|
||||
thing="bob lolo bibi and co", otherthing="lolo"
|
||||
),
|
||||
string="Replacement title", version="7.0"))
|
||||
|
||||
|
||||
+1
-1
@@ -2225,7 +2225,7 @@ class BaseModel(object):
|
||||
# if val is a many2one, just write the ID
|
||||
if type(val) == tuple:
|
||||
val = val[0]
|
||||
if val is not False:
|
||||
if f._type == 'boolean' or val is not False:
|
||||
cr.execute(update_query, (ss[1](val), key))
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -54,7 +54,12 @@ def check(f):
|
||||
if args and isinstance(args[-1], dict):
|
||||
ctx = args[-1]
|
||||
elif isinstance(kwargs, dict):
|
||||
ctx = kwargs.get('context', {})
|
||||
if 'context' in kwargs:
|
||||
ctx = kwargs['context']
|
||||
elif 'kwargs' in kwargs:
|
||||
# http entry points such as call_kw()
|
||||
ctx = kwargs['kwargs'].get('context')
|
||||
|
||||
|
||||
uid = 1
|
||||
if args and isinstance(args[0], (long, int)):
|
||||
|
||||
Reference in New Issue
Block a user