[MERGE] website_*: quick fixes for website_* module

Fix and imp based on the review of saas14 pad
Courtesy of @mge-odoo for the testing and reporting.
This commit is contained in:
Jeremy Kersten
2017-02-01 09:17:20 +01:00
17 changed files with 144 additions and 68 deletions
@@ -5,6 +5,7 @@ import datetime
import werkzeug
from collections import OrderedDict
from werkzeug.exceptions import NotFound
from odoo import fields
from odoo import http
@@ -93,13 +94,13 @@ class WebsiteAccount(website_account):
this_week_end_date = fields.Date.to_string(fields.Date.from_string(today) + datetime.timedelta(days=7))
searchbar_filters = {
'all': {'label': _('All'), 'domain': []},
'all': {'label': _('Active'), 'domain': []},
'today': {'label': _('Today Activities'), 'domain': [('activity_date_deadline', '=', today)]},
'week': {'label': _('This Week Activities'),
'domain': [('activity_date_deadline', '>=', today), ('activity_date_deadline', '<=', this_week_end_date)]},
'overdue': {'label': _('Overdue Activities'), 'domain': [('activity_date_deadline', '<', today)]},
'won': {'label': _('Won'), 'domain': [('stage_id.probability', '=', 100), ('stage_id.fold', '=', True)]},
'lost': {'label': _('Lost'), 'domain': [('active', '=', False)]},
'won': {'label': _('Won'), 'domain': [('stage_id.probability', '=', 100), ('stage_id.on_change', '=', True)]},
'lost': {'label': _('Lost'), 'domain': [('active', '=', False), ('probability', '=', 0)]},
}
searchbar_sortings = {
'date': {'label': _('Newest'), 'order': 'create_date desc'},
@@ -118,6 +119,8 @@ class WebsiteAccount(website_account):
if not filterby:
filterby = 'all'
domain += searchbar_filters[filterby]['domain']
if filterby == 'lost':
CrmLead = CrmLead.with_context(active_test=False)
# archive groups - Default Group By 'create_date'
archive_groups = self._get_archive_groups('crm.lead', domain)
@@ -149,16 +152,21 @@ class WebsiteAccount(website_account):
})
return request.render("website_crm_partner_assign.portal_my_opportunities", values)
@http.route(['/my/lead/<model("crm.lead"):lead>'], type='http', auth="user", website=True)
def portal_my_lead(self, lead=None, **kw):
@http.route(['''/my/lead/<model('crm.lead', "[('type','=', 'lead')]"):lead>'''], type='http', auth="user", website=True)
def portal_my_lead(self, lead, **kw):
if lead.type != 'lead':
raise NotFound()
return request.render("website_crm_partner_assign.portal_my_lead", {'lead': lead})
@http.route(['/my/opportunity/<model("crm.lead"):lead>'], type='http', auth="user", website=True)
def portal_my_opportunity(self, lead=None, **kw):
@http.route(['''/my/opportunity/<model('crm.lead', "[('type','=', 'opportunity')]"):opp>'''], type='http', auth="user", website=True)
def portal_my_opportunity(self, opp, **kw):
if opp.type != 'opportunity':
raise NotFound()
return request.render(
"website_crm_partner_assign.portal_my_opportunity", {
'opportunity': lead,
'user_activity': lead.activity_ids.filtered(lambda activity: activity.user_id == request.env.user)[:1],
'opportunity': opp,
'user_activity': opp.activity_ids.filtered(lambda activity: activity.user_id == request.env.user)[:1],
'stages': request.env['crm.stage'].search([('probability', '!=', '100')], order='sequence desc'),
'activity_types': request.env['mail.activity.type'].sudo().search([]),
'states': request.env['res.country.state'].sudo().search([]),
@@ -232,26 +232,29 @@ class CrmLead(models.Model):
'planned_revenue': values['planned_revenue'],
'probability': values['probability'],
'priority': values['priority'],
'date_deadline': values['date_deadline'] or False,
}
# As activities may belong to several users, only the current portal user activity
# will be modified by the portal form. If no activity exist we create a new one instead
# that we assign to the portal user.
user_activity = lead.activity_ids.filtered(lambda activity: activity.user_id == self.env.user)[:1]
if user_activity:
user_activity.sudo().write({
'activity_type_id': values['activity_type_id'],
'summary': values['activity_summary'],
'date_deadline': values['activity_date_deadline'],
})
else:
self.env['mail.activity'].sudo().create({
'res_model_id': self.env.ref('crm.model_crm_lead').id,
'res_id': lead.id,
'user_id': self.env.user.id,
'activity_type_id': values['activity_type_id'],
'summary': values['activity_summary'],
'date_deadline': values['activity_date_deadline'],
})
if values['activity_date_deadline']:
if user_activity:
user_activity.sudo().write({
'activity_type_id': values['activity_type_id'],
'summary': values['activity_summary'],
'date_deadline': values['activity_date_deadline'],
})
else:
self.env['mail.activity'].sudo().create({
'res_model_id': self.env.ref('crm.model_crm_lead').id,
'res_id': lead.id,
'user_id': self.env.user.id,
'activity_type_id': values['activity_type_id'],
'summary': values['activity_summary'],
'date_deadline': values['activity_date_deadline'],
})
lead.write(lead_values)
@api.model
@@ -101,6 +101,8 @@ $('.edit_contact_confirm').on('click',function(){
});
$('.new_opp_confirm').on('click',function(e){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("create_opp_portal", [{
contact_name: $('.new_opp_form .contact_name').val(),
@@ -111,10 +113,15 @@ $('.new_opp_confirm').on('click',function(e){
if (response.errors) {
$('#new-opp-dialog .alert').remove();
$('#new-opp-dialog div:first').prepend("<div class='alert alert-danger'>" + response.errors + "</div>");
$btn.prop('disabled', false);
}
else {
window.location = '/my/opportunity/' + response.id;
}
})
.fail(function() {
$btn.prop('disabled', false);
});
return false;
});
@@ -124,6 +131,7 @@ $('.edit_opp_confirm').on('click',function(){
$btn.prop('disabled', true);
new Model('crm.lead')
.call("update_lead_portal", [[parseInt($('.edit_opp_form .opportunity_id').val())],{
date_deadline: $('.edit_opp_form .date_deadline').val(),
planned_revenue: parseFloat($('.edit_opp_form .planned_revenue').val()),
probability: parseFloat($('.edit_opp_form .probability').val()),
activity_type_id: parseInt($('.edit_opp_form .next_activity').find(":selected").attr('data')),
@@ -215,7 +215,7 @@
<span class='badge'><t t-esc="lead_count"/></span>
</t>
<t t-if="not lead_count">
There are currently no leads for your account.
There are currently no leads.
</t>
</small>
</a>
@@ -227,7 +227,7 @@
<span class='badge'><t t-esc="opp_count"/></span>
</t>
<t t-if="not opp_count">
There are currently no opportunities for your account.
There are currently no opportunities.
</t>
</small>
</a>
@@ -307,13 +307,13 @@
</form>
</div>
</div>
<div class="panel panel-default">
<t t-if="not opportunities">
<div class="alert alert-warning mt8" role="alert">
There are no opportunities.
</div>
</t>
<table t-if="opportunities" class="table table-hover">
<t t-if="not opportunities">
<div class="alert alert-warning mt8" role="alert">
There are no opportunities.
</div>
</t>
<div class="panel panel-default" t-if="opportunities">
<table class="table table-hover">
<thead>
<tr class="active">
<th class="col-xs-2">Date</th>
+9 -2
View File
@@ -78,8 +78,15 @@ class WebsitePayment(http.Controller):
tx_id = request.session.pop('website_payment_tx_id', False)
if tx_id:
tx = request.env['payment.transaction'].browse(tx_id)
status = (tx.state == 'done' and 'success') or 'danger'
message = (tx.state == 'done' and 'Your payment was successful! It may take some time to be validated on our end.') or 'OOps! There was a problem with your payment.'
if tx.state == 'done':
status = 'success'
message = tx.acquirer_id.done_msg
elif tx.state == 'pending':
status = 'warning'
message = tx.acquirer_id.pending_msg
else:
status = 'danger'
message = tx.acquirer_id.error_msg
return request.render('website_payment.confirm', {'tx': tx, 'status': status, 'message': message})
else:
return request.redirect('/my/home')
@@ -136,7 +136,7 @@
<div class="row">
<div class="col-md-6">
<div class="form-horizontal">
<div t-attf-class="alert alert-#{status}" t-esc="message"/>
<div t-attf-class="alert alert-#{status}" t-raw="message"/>
<div class="form-group">
<label for="form_partner_name" class="col-sm-3 control-label">From</label>
<div class="col-sm-9">
@@ -0,0 +1,24 @@
odoo.define('website_portal.tour', function (require) {
'use strict';
var tour = require("web_tour.tour");
var base = require("web_editor.base");
tour.register('portal_load_homepage', {
test: true,
url: '/my',
wait_for: base.ready()
},
[
{
content: "Check portal is loaded",
trigger: 'a[href*="/my/account"]:contains("Change"):first',
},
{
content: "Load my account details",
trigger: 'body:contains("Contact Details")',
}
]
);
});
@@ -9,3 +9,7 @@
.o_my_home_content > .page-header > a:hover {
text-decoration: none;
}
.portal-wrap table.table tr {
word-wrap: break-word;
}
+1
View File
@@ -0,0 +1 @@
import test_load_process
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
@odoo.tests.common.at_install(False)
@odoo.tests.common.post_install(True)
class TestUi(odoo.tests.HttpCase):
def test_01_portal_load_tour(self):
self.phantom_js(
"/",
"odoo.__DEBUG__.services['web_tour.tour'].run('portal_load_homepage')",
"",
login="portal"
)
@@ -5,6 +5,7 @@
<xpath expr="." position="inside">
<link rel='stylesheet' href='/website_portal/static/src/less/website_portal.less'/>
<script type="text/javascript" src="/website_portal/static/src/js/website_portal.js"></script>
<script type="text/javascript" src="/website_portal/static/src/js/website_portal_tour.js"></script>
</xpath>
</template>
@@ -90,7 +91,7 @@
</div>
</div>
</div>
<div id="wrap">
<div id="wrap" class='portal-wrap'>
<div class="container mb64">
<div class="row">
<div class="col-md-9 col-lg-8">
@@ -9,7 +9,7 @@
<template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="website_portal.portal_layout" priority="25">
<xpath expr="//ul[contains(@class,'o_portal_submenu')]" position="inside">
<li t-att-class="page_name == 'quote' and 'active'">
<a href="/my/quotes">Quotes</a>
<a href="/my/quotes">Quotations</a>
</li>
<li t-att-class="page_name == 'order' and 'active'">
<a href="/my/orders">Orders</a>
@@ -23,13 +23,13 @@
<template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="website_portal.portal_my_home" priority="25">
<xpath expr="//div[contains(@class,'o_my_home_content')]" position="inside">
<h3 class="page-header">
<a href="/my/quotes">Your Quotes
<a href="/my/quotes">Your Quotations
<small class="ml8">
<t t-if="quotation_count">
<span class='badge'><t t-esc="quotation_count"/></span>
</t>
<t t-if="not quotation_count">
There are currently no quotes for your account.
There are currently no quotations.
</t>
</small>
</a>
@@ -41,7 +41,7 @@
<span class='badge'><t t-esc="order_count"/></span>
</t>
<t t-if="not order_count">
There are currently no orders for your account.
There are currently no orders.
</t>
</small>
</a>
@@ -53,7 +53,7 @@
<span class='badge'><t t-esc="invoice_count"/></span>
</t>
<t t-if="not invoice_count">
There are currently no invoices for your account.
There are currently no invoices and payments.
</t>
</small>
</a>
@@ -64,11 +64,11 @@
<template id="portal_my_quotations" name="My Quotations">
<t t-call="website_portal.portal_layout">
<div class="page-header">
<span class="h3">Your Quotes</span>
<span class="h3">Your Quotations</span>
<t t-call="website_portal.portal_searchbar"/>
</div>
<t t-if="not quotations">
<p>There are currently no quotes for your account.</p>
<p>There are currently no quotations for your account.</p>
</t>
<t t-if="quotations">
<div class="table-responsive"><table class="table table-hover o_my_status_table">
@@ -162,7 +162,7 @@
<t t-call="website_portal.portal_searchbar"/>
</div>
<t t-if="not invoices">
<p>There are currently no invoices for your account.</p>
<p>There are currently no invoices and payments for your account.</p>
</t>
<t t-if="invoices">
<div class="table-responsive"><table class="table table-hover o_my_status_table">
@@ -220,7 +220,7 @@
<li>
<a t-attf-href="/my/#{'quotes' if order.state == 'sent' else 'orders'}?{{ keep_query()}}">
<t t-if="order.state == 'sent'">
My Quotes
My Quotations
</t>
<t t-if="order.state != 'sent'">
My Orders
@@ -311,28 +311,28 @@
<div class="col-md-6">
<strong>Product</strong>
</div>
<div class="col-md-2 text-right">
<div class="hidden-sm hidden-xs col-md-2 text-right">
<strong>Unit Price</strong>
</div>
<div class="col-md-2 text-right">
<div class="hidden-sm hidden-xs col-md-2 text-right">
<strong>Quantity</strong>
</div>
<div class="col-md-2 text-right">
<div class="hidden-sm hidden-xs col-md-2 text-right">
<strong>Subtotal</strong>
</div>
</div>
<t t-foreach="order.order_line" t-as="ol">
<div class="row orders_vertical_align">
<div class="col-md-1 text-center">
<img t-att-src="'/web/image/product.product/%s/image_small/48x48' % ol.product_id.id"/>
<div class="visible-lg col-lg-1 text-center">
<span t-field="ol.product_id.image_small" t-options="{'widget': 'image', 'class': 'img-rounded', 'style':'width: 48px;height:48px'}" />
</div>
<div id='product_name' class="col-md-5">
<div id='product_name' class="col-lg-4 col-sm-6 col-xs-4">
<span t-esc="ol.product_id.name"/>
</div>
<div class="col-md-2 text-right">
<div class="col-xs-3 text-right">
<span t-field="ol.price_unit" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/>
</div>
<div class="col-md-2 text-right">
<div class="col-xs-2 text-right">
<t t-if="ol._name == 'sale.order.line'">
<span t-esc="ol.product_uom_qty"/>
</t>
@@ -340,7 +340,7 @@
<span t-esc="ol.quantity"/>
</t>
</div>
<div class="col-md-2 text-right">
<div class="col-sm-2 col-xs-3 text-right">
<span t-field="ol.price_subtotal" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/>
</div>
</div>
@@ -354,29 +354,30 @@
<strong>Contact</strong>
</div>
<div t-field="order.user_id.partner_id" t-options='{"widget": "contact", "fields": ["email", "phone"]}'/>
<br/>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-10 text-right">
<div class="col-md-10 col-xs-8 text-right">
Untaxed Amount:
</div>
<div class="col-md-2 text-right">
<div class="col-md-2 col-xs-4 text-right">
<span t-field="order.amount_untaxed" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/>
</div>
</div>
<div class="row">
<div class="col-md-10 text-right">
<div class="col-md-10 col-xs-8 text-right">
Taxes:
</div>
<div class="col-md-2 text-right">
<div class="col-md-2 col-xs-4 text-right">
<span t-field="order.amount_tax" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/>
</div>
</div>
<div class="row">
<div class="col-md-10 text-right">
<div class="col-md-10 col-xs-8 text-right">
<strong>Total:</strong>
</div>
<div class="col-md-2 text-right">
<div class="col-md-2 col-xs-4 text-right">
<strong><span t-field="order.amount_total" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/></strong>
</div>
</div>
@@ -20,7 +20,7 @@
<span class='badge'><t t-esc="project_count"/></span>
</t>
<t t-if="not project_count">
There are currently no projects for your account.
There are currently no projects.
</t>
</small>
</a>
@@ -32,7 +32,7 @@
<span class='badge'><t t-esc="task_count"/></span>
</t>
<t t-if="not task_count">
There are currently no quotes for your account.
There are currently no quotes.
</t>
</small>
</a>
@@ -18,7 +18,7 @@
<span class='badge'><t t-esc="issue_count"/></span>
</t>
<t t-if="not issue_count">
There are currently no issues for your account.
There are currently no issues.
</t>
</small>
</a>
@@ -201,11 +201,13 @@ odoo.define('website_sale.website_sale', function (require) {
$('.oe_website_sale .a-submit, #comment .a-submit').off('click').on('click', function (event) {
if (!event.isDefaultPrevented() && !$(this).is(".disabled")) {
event.preventDefault();
$(this).closest('form').submit();
}
});
$('form.js_attributes input, form.js_attributes select', oe_website_sale).on('change', function (event) {
if (!event.isDefaultPrevented()) {
event.preventDefault();
$(this).closest("form").submit();
}
});
+4 -3
View File
@@ -1151,6 +1151,7 @@
</template>
<template id="address" name="Address Management">
<t t-set="no_footer">1</t>
<t t-call="website.layout">
<div id="wrap">
<div class="container oe_website_sale">
@@ -1163,17 +1164,17 @@
<div class="col-md-9 oe_cart">
<div class="row">
<t t-if="mode == ('new', 'billing')">
<h2 class="page-header mt16">Your Address
<h2 class="page-header mt16 ml16">Your Address
<small> or </small>
<t t-set='connect' t-value="request.env['ir.config_parameter'].sudo().get_param('auth_signup.allow_uninvited') == 'True' and ('signup', 'Sign Up') or ('login', 'Log In')"/>
<a t-attf-href='/web/{{connect[0]}}?redirect=/shop/checkout' class='btn btn-primary' style="margin-top: -11px"><t t-esc='connect[1]'/></a>
</h2>
</t>
<t t-if="mode == ('edit', 'billing')">
<h2 class="page-header mt16">Your Address</h2>
<h2 class="page-header mt16 ml16">Your Address</h2>
</t>
<t t-if="mode[1] == 'shipping'">
<h2 class="page-header mt16">Shipping Address </h2>
<h2 class="page-header mt16 ml16">Shipping Address </h2>
</t>
<t t-if="error" t-foreach="error.get('error_message', [])" t-as="err">
<h4 class="text-danger" t-esc="err" />
+1 -1
View File
@@ -102,7 +102,7 @@ class IrUiMenu(models.Model):
'ir.actions.report.xml': lambda action: action.model,
'ir.actions.server': lambda action: action.model_id.model,
}
for menu in action_menus:
for menu in action_menus.sudo():
get_model = MODEL_GETTER.get(menu.action._name)
if not get_model or not get_model(menu.action) or \
access.check(get_model(menu.action), 'read', False):