[MERGE] forward port of branch saas-5 up to 655a5b9

This commit is contained in:
Denis Ledoux 2014-08-04 16:56:10 +02:00
commit 1bb219907f
22 changed files with 179 additions and 101 deletions

View File

@ -140,6 +140,7 @@ class PaymentAcquirer(osv.Model):
'country': tx.partner_country_id, 'country': tx.partner_country_id,
'phone': tx.partner_phone, 'phone': tx.partner_phone,
'reference': tx.partner_reference, 'reference': tx.partner_reference,
'state': None,
} }
else: else:
if partner_id: if partner_id:
@ -154,6 +155,7 @@ class PaymentAcquirer(osv.Model):
'country_id': partner.country_id.id, 'country_id': partner.country_id.id,
'country': partner.country_id, 'country': partner.country_id,
'phone': partner.phone, 'phone': partner.phone,
'state': partner.state_id,
} }
else: else:
partner, partner_data = False, {} partner, partner_data = False, {}

View File

@ -118,6 +118,7 @@ class AcquirerPaypal(osv.Model):
'address1': partner_values['address'], 'address1': partner_values['address'],
'city': partner_values['city'], 'city': partner_values['city'],
'country': partner_values['country'] and partner_values['country'].name or '', 'country': partner_values['country'] and partner_values['country'].name or '',
'state': partner_values['state'] and partner_values['state'].name or '',
'email': partner_values['email'], 'email': partner_values['email'],
'zip': partner_values['zip'], 'zip': partner_values['zip'],
'first_name': partner_values['first_name'], 'first_name': partner_values['first_name'],
@ -226,7 +227,7 @@ class TxPaypal(osv.Model):
# check seller # check seller
if data.get('receiver_email') != tx.acquirer_id.paypal_email_account: if data.get('receiver_email') != tx.acquirer_id.paypal_email_account:
invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account)) invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account))
if tx.acquirer_id.paypal_seller_account and data.get('receiver_id') != tx.acquirer_id.paypal_seller_account: if data.get('receiver_id') and tx.acquirer_id.paypal_seller_account and data['receiver_id'] != tx.acquirer_id.paypal_seller_account:
invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account)) invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account))
return invalid_parameters return invalid_parameters

View File

@ -1376,16 +1376,4 @@ class product_template(osv.osv):
'available_in_pos': True, 'available_in_pos': True,
} }
def edit_ean(self, cr, uid, ids, context):
return {
'name': _("Assign a Custom EAN"),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'pos.ean_wizard',
'target' : 'new',
'view_id': False,
'context':context,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -521,6 +521,13 @@
<menuitem action="product_pos_category_action" id="menu_product_pos_category" parent="menu_point_of_sale_product" sequence="0" /> <menuitem action="product_pos_category_action" id="menu_product_pos_category" parent="menu_point_of_sale_product" sequence="0" />
<!-- END --> <!-- END -->
<record id="action_edit_ean" model="ir.actions.act_window">
<field name="name">Edit Ean</field>
<field name="res_model">pos.ean_wizard</field>
<field name="target">new</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
</record>
<record id="product_template_form_view" model="ir.ui.view"> <record id="product_template_form_view" model="ir.ui.view">
<field name="name">product.template.form.inherit</field> <field name="name">product.template.form.inherit</field>
@ -537,7 +544,7 @@
</group> </group>
</group> </group>
<field name="ean13" position="after"> <field name="ean13" position="after">
<button colspan="2" name="edit_ean" type="object" string="Set a Custom EAN" class="oe_link oe_edit_only"/> <button colspan="2" name="%(action_edit_ean)d" type="action" string="Set a Custom EAN" class="oe_link oe_edit_only"/>
</field> </field>
</field> </field>
</record> </record>

View File

@ -18,18 +18,6 @@ class res_users(osv.osv):
for user in self.browse(cr, uid, ids, context=context) for user in self.browse(cr, uid, ids, context=context)
) )
def edit_ean(self, cr, uid, ids, context):
return {
'name': "Edit Ean",
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'pos.ean_wizard',
'target' : 'new',
'view_id': False,
'context':context,
}
_constraints = [ _constraints = [
(_check_ean, "Error: Invalid ean code", ['ean13'],), (_check_ean, "Error: Invalid ean code", ['ean13'],),
] ]

View File

@ -11,7 +11,7 @@
<page string="Point of Sale"> <page string="Point of Sale">
<group> <group>
<field name="ean13" /> <field name="ean13" />
<button name="edit_ean" type="object" string="Edit" /> <button name="%(action_edit_ean)d" type="action" string="Set a Custom EAN" />
</group> </group>
</page> </page>
</notebook> </notebook>

View File

@ -19,18 +19,6 @@ class res_users(osv.osv):
for user in self.browse(cr, uid, ids, context=context) for user in self.browse(cr, uid, ids, context=context)
) )
def edit_ean(self, cr, uid, ids, context):
return {
'name': "Edit EAN",
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'pos.ean_wizard',
'target' : 'new',
'view_id': False,
'context':context,
}
_constraints = [ _constraints = [
(_check_ean, "Error: Invalid ean code", ['ean13'],), (_check_ean, "Error: Invalid ean code", ['ean13'],),
] ]

View File

@ -23,7 +23,7 @@
<group> <group>
<field name="pos_config" /> <field name="pos_config" />
<field name="ean13" /> <field name="ean13" />
<button name="edit_ean" type="object" string="Edit EAN" class="oe_edit_only" /> <button name="%(action_edit_ean)d" type="action" string="Set a Custom EAN" class="oe_edit_only" />
</group> </group>
</page> </page>
</notebook> </notebook>

View File

@ -424,13 +424,7 @@ class product_template(osv.osv):
return self._is_product_variant_impl(cr, uid, ids, name, arg, context=context) return self._is_product_variant_impl(cr, uid, ids, name, arg, context=context)
def _is_product_variant_impl(self, cr, uid, ids, name, arg, context=None): def _is_product_variant_impl(self, cr, uid, ids, name, arg, context=None):
prod = self.pool.get('product.product') return dict.fromkeys(ids, False)
res = dict.fromkeys(ids, False)
ctx = dict(context, active_test=True)
for product in self.browse(cr, uid, ids, context=context):
res[product.id] = prod.search(cr, uid, [('product_tmpl_id','=',product.id)], context=ctx, count=True) == 1
return res
def _product_template_price(self, cr, uid, ids, name, arg, context=None): def _product_template_price(self, cr, uid, ids, name, arg, context=None):
plobj = self.pool.get('product.pricelist') plobj = self.pool.get('product.pricelist')

View File

@ -31,7 +31,7 @@
<span t-field="o.name"/> <span t-field="o.name"/>
</h2> </h2>
<div class="row mt32 mb32"> <div class="row mt32 mb32" id="informations">
<div t-if="o.client_order_ref" class="col-xs-3"> <div t-if="o.client_order_ref" class="col-xs-3">
<strong>Your Reference:</strong> <strong>Your Reference:</strong>
<p t-field="o.client_order_ref"/> <p t-field="o.client_order_ref"/>
@ -45,10 +45,6 @@
<strong>Salesperson:</strong> <strong>Salesperson:</strong>
<p t-field="o.user_id.name"/> <p t-field="o.user_id.name"/>
</div> </div>
<div t-if="o.validity_date" class="col-xs-3">
<strong>Validity Date:</strong>
<p t-field="o.validity_date"/>
</div>
<div t-if="o.payment_term" class="col-xs-3"> <div t-if="o.payment_term" class="col-xs-3">
<strong>Payment Term:</strong> <strong>Payment Term:</strong>
<p t-field="o.payment_term"/> <p t-field="o.payment_term"/>

View File

@ -3,12 +3,15 @@ import cStringIO
import datetime import datetime
from itertools import islice from itertools import islice
import json import json
import xml.etree.ElementTree as ET
import logging import logging
import re import re
from sys import maxint from sys import maxint
import werkzeug.utils import werkzeug.utils
import urllib2
import werkzeug.wrappers import werkzeug.wrappers
from PIL import Image from PIL import Image
@ -353,6 +356,20 @@ class Website(openerp.addons.web.controllers.main.Home):
obj = _object.browse(request.cr, request.uid, _id) obj = _object.browse(request.cr, request.uid, _id)
return bool(obj.website_published) return bool(obj.website_published)
@http.route(['/website/seo_suggest/<keywords>'], type='http', auth="public", website=True)
def seo_suggest(self, keywords):
url = "http://google.com/complete/search"
param = {
'ie': 'utf8',
'oe': 'utf8',
'output': 'toolbar',
'q': keywords
}
req = urllib2.Request("%s?%s" % (url, werkzeug.url_encode(param)))
request = urllib2.urlopen(req)
xmlroot = ET.fromstring(request.read())
return json.dumps([sugg[0].attrib['data'] for sugg in xmlroot if len(sugg) and sugg[0].attrib['data']])
#------------------------------------------------------ #------------------------------------------------------
# Helpers # Helpers
#------------------------------------------------------ #------------------------------------------------------

View File

@ -522,12 +522,15 @@ div.media_iframe_video {
div.media_iframe_video iframe { div.media_iframe_video iframe {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute;
margin-left: -50%;
} }
div.media_iframe_video div { div.media_iframe_video .css_editable_mode_display {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: none; display: none;
z-index: 2;
} }
/* Mobile view */ /* Mobile view */

View File

@ -99,7 +99,7 @@ header
margin-right: 0 !important margin-right: 0 !important
.css_non_editable_mode_hidden .css_non_editable_mode_hidden
display: none display: none !important
/* ----- BOOTSTRAP FIX ----- */ /* ----- BOOTSTRAP FIX ----- */
@ -424,11 +424,14 @@ div.media_iframe_video
iframe iframe
width: 100% width: 100%
height: 100% height: 100%
div position: absolute
margin-left: -50%
.css_editable_mode_display
position: absolute position: absolute
width: 100% width: 100%
height: 100% height: 100%
display: none display: none
z-index: 2
/* Mobile view */ /* Mobile view */

View File

@ -86,7 +86,7 @@
} }
}); });
} }
$.getJSON("http://suggest.hp.af.cm/suggest/"+encodeURIComponent(this.root + " "), addSuggestions); $.getJSON("/website/seo_suggest/" + encodeURIComponent(this.root + " "), addSuggestions);
}, },
}); });

View File

@ -13,6 +13,7 @@ OpenERP Sale Quote Roller
'data': [ 'data': [
'views/website_quotation.xml', 'views/website_quotation.xml',
'views/website_quotation_backend.xml', 'views/website_quotation_backend.xml',
'views/report_saleorder.xml',
'data/website_quotation_data.xml', 'data/website_quotation_data.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
], ],

View File

@ -114,7 +114,7 @@ class sale_order(osv.osv):
'template_id': fields.many2one('sale.quote.template', 'Quote Template'), 'template_id': fields.many2one('sale.quote.template', 'Quote Template'),
'website_description': fields.html('Description'), 'website_description': fields.html('Description'),
'options' : fields.one2many('sale.order.option', 'order_id', 'Optional Products Lines'), 'options' : fields.one2many('sale.order.option', 'order_id', 'Optional Products Lines'),
'validity_date': fields.date('Validity Date'), 'validity_date': fields.date('Expiry Date'),
'amount_undiscounted': fields.function(_get_total, string='Amount Before Discount', type="float", 'amount_undiscounted': fields.function(_get_total, string='Amount Before Discount', type="float",
digits_compute=dp.get_precision('Account')) digits_compute=dp.get_precision('Account'))
} }

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_saleorder_validity_date" inherit_id="sale.report_saleorder_document">
<xpath expr="//div[@class='page']/div[@id='informations']" position="inside">
<div t-if="o.validity_date" class="col-xs-3">
<strong>Expiry Date:</strong>
<p t-field="o.validity_date"/>
</div>
</xpath>
</template>
</data>
</openerp>

View File

@ -346,18 +346,17 @@ class website_sale(http.Controller):
countries = orm_country.browse(cr, SUPERUSER_ID, country_ids, context) countries = orm_country.browse(cr, SUPERUSER_ID, country_ids, context)
states_ids = state_orm.search(cr, SUPERUSER_ID, [], context=context) states_ids = state_orm.search(cr, SUPERUSER_ID, [], context=context)
states = state_orm.browse(cr, SUPERUSER_ID, states_ids, context) states = state_orm.browse(cr, SUPERUSER_ID, states_ids, context)
partner = orm_user.browse(cr, SUPERUSER_ID, request.uid, context).partner_id
order = None
shipping_id = None
shipping_ids = []
checkout = {} checkout = {}
if not data: if not data:
if request.uid != request.website.user_id.id: if request.uid != request.website.user_id.id:
partner = orm_user.browse(cr, SUPERUSER_ID, request.uid, context).partner_id
checkout.update( self.checkout_parse("billing", partner) ) checkout.update( self.checkout_parse("billing", partner) )
shipping_ids = orm_partner.search(cr, SUPERUSER_ID, [("parent_id", "=", partner.id), ('type', "=", 'delivery')], context=context)
shipping_ids = orm_partner.search(cr, SUPERUSER_ID, [("parent_id", "=", partner.id), ('type', "=", 'delivery')], limit=1, context=context)
if shipping_ids:
shipping = orm_user.browse(cr, SUPERUSER_ID, request.uid, context)
checkout.update( self.checkout_parse("shipping", shipping) )
checkout['shipping_different'] = True
else: else:
order = request.website.sale_get_order(force_create=1, context=context) order = request.website.sale_get_order(force_create=1, context=context)
if order.partner_id: if order.partner_id:
@ -367,9 +366,37 @@ class website_sale(http.Controller):
checkout.update( self.checkout_parse("billing", order.partner_id) ) checkout.update( self.checkout_parse("billing", order.partner_id) )
else: else:
checkout = self.checkout_parse('billing', data) checkout = self.checkout_parse('billing', data)
if data.get("shipping_different"): try:
shipping_id = int(data["shipping_id"])
except ValueError:
pass
if shipping_id == -1:
checkout.update(self.checkout_parse('shipping', data)) checkout.update(self.checkout_parse('shipping', data))
checkout["shipping_different"] = True
if shipping_id is None:
if not order:
order = request.website.sale_get_order(context=context)
if order and order.partner_shipping_id:
shipping_id = order.partner_shipping_id.id
shipping_ids = list(set(shipping_ids) - set([partner.id]))
if shipping_id == partner.id:
shipping_id = 0
elif shipping_id > 0 and shipping_id not in shipping_ids:
shipping_ids.append(shipping_id)
elif shipping_id is None and shipping_ids:
shipping_id = shipping_ids[0]
ctx = dict(context, show_address=1)
shippings = []
if shipping_ids:
shippings = shipping_ids and orm_partner.browse(cr, SUPERUSER_ID, list(shipping_ids), ctx) or []
if shipping_id > 0:
shipping = orm_partner.browse(cr, SUPERUSER_ID, shipping_id, ctx)
checkout.update( self.checkout_parse("shipping", shipping) )
checkout['shipping_id'] = shipping_id
# Default search by user country # Default search by user country
country_code = request.session['geoip'].get('country_code') country_code = request.session['geoip'].get('country_code')
@ -382,10 +409,12 @@ class website_sale(http.Controller):
'countries': countries, 'countries': countries,
'states': states, 'states': states,
'checkout': checkout, 'checkout': checkout,
'shipping_different': checkout.get('shipping_different'), 'shipping_id': partner.id != shipping_id and shipping_id or 0,
'shippings': shippings,
'error': {}, 'error': {},
'has_check_vat': hasattr(registry['res.partner'], 'check_vat') 'has_check_vat': hasattr(registry['res.partner'], 'check_vat')
} }
return values return values
mandatory_billing_fields = ["name", "phone", "email", "street", "city", "country_id", "zip"] mandatory_billing_fields = ["name", "phone", "email", "street", "city", "country_id", "zip"]
@ -445,7 +474,7 @@ class website_sale(http.Controller):
if not check_func(cr, uid, vat_country, vat_number, context=None): # simple_vat_check if not check_func(cr, uid, vat_country, vat_number, context=None): # simple_vat_check
error["vat"] = 'error' error["vat"] = 'error'
if data.get("shipping_different"): if data.get("shipping_id") == -1:
for field_name in self.mandatory_shipping_fields: for field_name in self.mandatory_shipping_fields:
field_name = 'shipping_' + field_name field_name = 'shipping_' + field_name
if not data.get(field_name): if not data.get(field_name):
@ -482,23 +511,22 @@ class website_sale(http.Controller):
partner_id = orm_partner.create(cr, SUPERUSER_ID, billing_info, context=context) partner_id = orm_partner.create(cr, SUPERUSER_ID, billing_info, context=context)
# create a new shipping partner # create a new shipping partner
shipping_id = None if checkout.get('shipping_id') == -1:
if checkout.get('shipping_different'):
shipping_info = self.checkout_parse('shipping', checkout, True) shipping_info = self.checkout_parse('shipping', checkout, True)
shipping_info['type'] = 'delivery' shipping_info['type'] = 'delivery'
shipping_info['parent_id'] = partner_id shipping_info['parent_id'] = partner_id
shipping_id = orm_partner.create(cr, SUPERUSER_ID, shipping_info, context) checkout['shipping_id'] = orm_partner.create(cr, SUPERUSER_ID, shipping_info, context)
order_info = { order_info = {
'partner_id': partner_id, 'partner_id': partner_id,
'message_follower_ids': [(4, partner_id)], 'message_follower_ids': [(4, partner_id)],
'partner_invoice_id': partner_id, 'partner_invoice_id': partner_id,
'partner_shipping_id': shipping_id or partner_id
} }
order_info.update(order_obj.onchange_partner_id(cr, SUPERUSER_ID, [], partner_id, context=context)['value']) order_info.update(order_obj.onchange_partner_id(cr, SUPERUSER_ID, [], partner_id, context=context)['value'])
order_info.update(order_obj.onchange_delivery_id(cr, SUPERUSER_ID, [], order.company_id.id, partner_id, shipping_id, None, context=context)['value']) order_info.update(order_obj.onchange_delivery_id(cr, SUPERUSER_ID, [], order.company_id.id, partner_id, checkout.get('shipping_id'), None, context=context)['value'])
order_info.pop('user_id') order_info.pop('user_id')
order_info.update(partner_shipping_id=checkout.get('shipping_id') or partner_id)
order_obj.write(cr, SUPERUSER_ID, [order.id], order_info, context=context) order_obj.write(cr, SUPERUSER_ID, [order.id], order_info, context=context)
@ -535,6 +563,7 @@ class website_sale(http.Controller):
return request.website.render("website_sale.checkout", values) return request.website.render("website_sale.checkout", values)
self.checkout_form_save(values["checkout"]) self.checkout_form_save(values["checkout"])
request.session['sale_last_order_id'] = order.id request.session['sale_last_order_id'] = order.id
request.website.sale_get_order(update_pricelist=True, context=context) request.website.sale_get_order(update_pricelist=True, context=context)

View File

@ -2,12 +2,19 @@ $(document).ready(function () {
$('.oe_website_sale').each(function () { $('.oe_website_sale').each(function () {
var oe_website_sale = this; var oe_website_sale = this;
var $shippingDifferent = $("input[name='shipping_different']", oe_website_sale); var $shippingDifferent = $("select[name='shipping_id']", oe_website_sale);
if ($shippingDifferent.is(':checked')) { $shippingDifferent.change(function (event) {
$(".js_shipping", oe_website_sale).show(); var value = +$shippingDifferent.val();
} var data = $shippingDifferent.find("option:selected").data();
$shippingDifferent.change(function () { var $snipping = $(".js_shipping", oe_website_sale);
$(".js_shipping", oe_website_sale).toggle(); var $inputs = $snipping.find("input,select");
$snipping.toggle(!!value);
$inputs.attr("readonly", value <= 0 ? null : "readonly" ).prop("readonly", value <= 0 ? null : "readonly" );
$inputs.each(function () {
$(this).val( data[$(this).attr("name")] || "" );
});
}); });
// change for css // change for css

View File

@ -916,40 +916,61 @@
<div class="clearfix"/> <div class="clearfix"/>
<div class="form-group col-lg-6"> <div class="form-group col-lg-12">
<label> <label>Shipping</label>
<input type="checkbox" name="shipping_different" t-att-checked="checkout.get('shipping_different')"/> <select name="shipping_id" class="form-control">
<span>Ship to a different address</span> <option value="0">Ship to the same address</option>
</label> <t t-foreach="shippings" t-as="shipping">
<option t-att-value="shipping.id" t-att-selected="shipping.id == shipping_id"
t-att-data-shipping_name="shipping.name"
t-att-data-shipping_phone="shipping.phone"
t-att-data-shipping_street="shipping.street"
t-att-data-shipping_city="shipping.city"
t-att-data-shipping_zip="shipping.zip"
t-att-data-shipping_state_id="shipping.state_id and shipping.state_id.id"
t-att-data-shipping_country_id="shipping.country_id and shipping.country_id.id"
><t t-esc="', '.join('\n'.join(shipping.name_get()[0][1].split(',')).split('\n')[1:])"/></option>
</t>
<option value="-1">-- Create a new address --</option>
</select>
</div> </div>
</div> </div>
<div class="js_shipping row mb16" t-att-style="not checkout.get('shipping_different') and 'display:none' or ''"> <div class="js_shipping row mb16" t-att-style="not shipping_id and 'display:none' or ''">
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3> <h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_name">Name (Shipping)</label> <label class="control-label" for="shipping_name">Name (Shipping)</label>
<input type="text" name="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')"/> <input type="text" name="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')" t-att-readonly="'readonly' if shipping_id &gt;= 0 else ''"/>
</div> </div>
<div t-attf-class="form-group #{error.get('shipping_phone') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_phone">Phone</label> <label class="control-label" for="shipping_phone">Phone</label>
<input type="tel" name="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')"/> <input type="tel" name="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''"/>
</div> </div>
<div t-attf-class="form-group #{error.get('shipping_street') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_street">Street</label> <label class="control-label" for="shipping_street">Street</label>
<input type="text" name="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')"/> <input type="text" name="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''"/>
</div> </div>
<div class="clearfix"/> <div class="clearfix"/>
<div t-attf-class="form-group #{error.get('shipping_city') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_city">City</label> <label class="control-label" for="shipping_city">City</label>
<input type="text" name="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')"/> <input type="text" name="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''"/>
</div> </div>
<div t-attf-class="form-group #{error.get('shipping_zip') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_zip">Zip / Postal Code</label> <label class="control-label" for="shipping_zip">Zip / Postal Code</label>
<input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/> <input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_state_id" style="font-weight: normal">State / Province</label>
<select name="shipping_state_id" class="form-control" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div> </div>
<div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''} col-lg-6"> <div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="shipping_country_id">Country</label> <label class="control-label" for="shipping_country_id">Country</label>
<select name="shipping_country_id" class="form-control"> <select name="shipping_country_id" class="form-control" t-att-readonly=" 'readonly' if shipping_id &gt;= 0 else ''">
<option value="">Country...</option> <option value="">Country...</option>
<t t-foreach="countries or []" t-as="country"> <t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('shipping_country_id')"><t t-esc="country.name"/></option> <option t-att-value="country.id" t-att-selected="country.id == checkout.get('shipping_country_id')"><t t-esc="country.name"/></option>
@ -966,8 +987,10 @@
</select> </select>
</div> </div>
</div> </div>
<a href="/shop/cart" class="btn btn-default mb32"><span class="fa fa-long-arrow-left"/> Return to Cart</a> <div class="clearfix">
<a class="btn btn-default btn-primary pull-right mb32 a-submit">Confirm <span class="fa fa-long-arrow-right"/></a> <a href="/shop/cart" class="btn btn-default mb32"><span class="fa fa-long-arrow-left"/> Return to Cart</a>
<a class="btn btn-default btn-primary pull-right mb32 a-submit">Confirm <span class="fa fa-long-arrow-right"/></a>
</div>
</div> </div>
<div class="col-lg-offset-1 col-lg-3 col-md-3 text-muted"> <div class="col-lg-offset-1 col-lg-3 col-md-3 text-muted">
<h3 class="page-header mt16">Your Order <small><a href="/shop/cart"><span class="fa fa-arrow-right"/> change</a></small></h3> <h3 class="page-header mt16">Your Order <small><a href="/shop/cart"><span class="fa fa-arrow-right"/> change</a></small></h3>

View File

@ -450,17 +450,31 @@ class res_partner(osv.Model, format_address):
def _commercial_sync_from_company(self, cr, uid, partner, context=None): def _commercial_sync_from_company(self, cr, uid, partner, context=None):
""" Handle sync of commercial fields when a new parent commercial entity is set, """ Handle sync of commercial fields when a new parent commercial entity is set,
as if they were related fields """ as if they were related fields """
if partner.commercial_partner_id != partner: commercial_partner = partner.commercial_partner_id
if not commercial_partner:
# On child partner creation of a parent partner,
# the commercial_partner_id is not yet computed
commercial_partner_id = self._commercial_partner_compute(
cr, uid, [partner.id], 'commercial_partner_id', [], context=context)[partner.id]
commercial_partner = self.browse(cr, uid, commercial_partner_id, context=context)
if commercial_partner != partner:
commercial_fields = self._commercial_fields(cr, uid, context=context) commercial_fields = self._commercial_fields(cr, uid, context=context)
sync_vals = self._update_fields_values(cr, uid, partner.commercial_partner_id, sync_vals = self._update_fields_values(cr, uid, commercial_partner,
commercial_fields, context=context) commercial_fields, context=context)
partner.write(sync_vals) partner.write(sync_vals)
def _commercial_sync_to_children(self, cr, uid, partner, context=None): def _commercial_sync_to_children(self, cr, uid, partner, context=None):
""" Handle sync of commercial fields to descendants """ """ Handle sync of commercial fields to descendants """
commercial_fields = self._commercial_fields(cr, uid, context=context) commercial_fields = self._commercial_fields(cr, uid, context=context)
sync_vals = self._update_fields_values(cr, uid, partner.commercial_partner_id, commercial_partner = partner.commercial_partner_id
commercial_fields, context=context) if not commercial_partner:
# On child partner creation of a parent partner,
# the commercial_partner_id is not yet computed
commercial_partner_id = self._commercial_partner_compute(
cr, uid, [partner.id], 'commercial_partner_id', [], context=context)[partner.id]
commercial_partner = self.browse(cr, uid, commercial_partner_id, context=context)
sync_vals = self._update_fields_values(cr, uid, commercial_partner,
commercial_fields, context=context)
sync_children = [c for c in partner.child_ids if not c.is_company] sync_children = [c for c in partner.child_ids if not c.is_company]
for child in sync_children: for child in sync_children:
self._commercial_sync_to_children(cr, uid, child, context=context) self._commercial_sync_to_children(cr, uid, child, context=context)

View File

@ -250,20 +250,24 @@ class test_base(common.TransactionCase):
'parent_id': p1.id})) 'parent_id': p1.id}))
p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid, p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid,
[('email', '=', 'agr@sunhelm.com')])[0]) [('email', '=', 'agr@sunhelm.com')])[0])
self.res_partner.write(cr, uid, sunhelm.id, {'child_ids': [(0, 0, {'name': 'Ulrik Greenthorn',
'email': 'ugr@sunhelm.com'})]})
p3 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid,
[('email', '=', 'ugr@sunhelm.com')])[0])
for p in (p0, p1, p11, p2): for p in (p0, p1, p11, p2, p3):
p.refresh() p.refresh()
self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution') self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution')
self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced') self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced')
sunhelmvat = 'BE0123456789' sunhelmvat = 'BE0123456789'
sunhelm.write({'vat': sunhelmvat}) sunhelm.write({'vat': sunhelmvat})
for p in (p0, p1, p11, p2): for p in (p0, p1, p11, p2, p3):
p.refresh() p.refresh()
self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced') self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced')
p1vat = 'BE0987654321' p1vat = 'BE0987654321'
p1.write({'vat': p1vat}) p1.write({'vat': p1vat})
for p in (sunhelm, p0, p11, p2): for p in (sunhelm, p0, p11, p2, p3):
p.refresh() p.refresh()
self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities') self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities')