[MERGE] portal,project,website_*: move portal code
This merge mainly does 2 things: - move frontend chatter feature from website_mail into portal, since chatter is required for some business model in the customer portal. This chatter is still also responsible of displaying comments for website object (slides, blog, ...) - bring project customer portal into project, and make project module depends on portal, like it was already done for sale and account. hr_timesheet now contains the dislaying of timesheet on task in portal. website_project is removed, and we do not use website.published.mixin on project, since this is only used to display its rating. projects are not public object.
This commit is contained in:
@@ -27,6 +27,7 @@ up a management by affair.
|
||||
'views/hr_timesheet_views.xml',
|
||||
'views/hr_timesheet_config_settings_views.xml',
|
||||
'views/project_views.xml',
|
||||
'views/project_portal_templates.xml',
|
||||
'report/hr_timesheet_report_view.xml',
|
||||
'report/report_timesheet_templates.xml',
|
||||
'views/hr_views.xml',
|
||||
|
||||
@@ -51,6 +51,21 @@
|
||||
<field name="perm_read" eval="1"/>
|
||||
</record>
|
||||
|
||||
<record id="timesheet_rule_portal" model="ir.rule">
|
||||
<field name="name">Project/Task Timesheets: frontend access</field>
|
||||
<field name="model_id" ref="analytic.model_account_analytic_line"/>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
'&',
|
||||
('task_id.project_id.privacy_visibility', '=', 'portal'),
|
||||
('task_id.project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
'&',
|
||||
('task_id.project_id.privacy_visibility', '=', 'portal'),
|
||||
('task_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
</odoo>
|
||||
@@ -1,8 +1,9 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_account_analytic_line_user,analytic.account.analytic.line.timesheet.user,analytic.model_account_analytic_line,hr_timesheet.group_hr_timesheet_user,1,1,1,1
|
||||
access_account_analytic_line_portal,access_timesheets_portal,analytic.model_account_analytic_line,base.group_portal,1,0,0,0
|
||||
access_account_analytic_user,analytic.account.analytic.timesheet.user,analytic.model_account_analytic_account,hr_timesheet.group_hr_timesheet_user,1,1,0,0
|
||||
access_product_product_user,product.product.timesheet.user,product.model_product_product,hr_timesheet.group_hr_timesheet_user,1,1,1,0
|
||||
access_product_template_timesheet_user,product.template.timesheet.user,product.model_product_template,hr_timesheet.group_hr_timesheet_user,1,1,1,0
|
||||
access_product_uom_hr_timesheet,product.uom.timesheet.user,product.model_product_uom,hr_timesheet.group_hr_timesheet_user,1,0,0,0
|
||||
access_project_project,project.project.timesheet.user,model_project_project,hr_timesheet.group_hr_timesheet_user,1,0,0,0
|
||||
access_project_task,project.task.timesheet.user,model_project_task,hr_timesheet.group_hr_timesheet_user,1,1,0,0
|
||||
access_project_task,project.task.timesheet.user,model_project_task,hr_timesheet.group_hr_timesheet_user,1,1,0,0
|
||||
|
||||
|
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="my_task" inherit_id="website_project.my_task" name="Project Task Timesheets">
|
||||
<template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with imesheets">
|
||||
<xpath expr="//div[hasclass('panel-body')]" position="inside">
|
||||
<div class="container" t-if="task.timesheet_ids">
|
||||
<hr/>
|
||||
@@ -178,6 +178,16 @@ class IrHttp(models.AbstractModel):
|
||||
|
||||
rerouting_limit = 10
|
||||
|
||||
@classmethod
|
||||
def _get_converters(cls):
|
||||
""" Get the converters list for custom url pattern werkzeug need to
|
||||
match Rule. This override adds the website ones.
|
||||
"""
|
||||
return dict(
|
||||
super(IrHttp, cls)._get_converters(),
|
||||
model=ModelConverter,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _get_languages(cls):
|
||||
return request.env['res.lang'].search([])
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
|
||||
from . import web
|
||||
from . import portal
|
||||
from . import mail
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from werkzeug.exceptions import NotFound, Forbidden
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.tools import consteq
|
||||
|
||||
|
||||
def _special_access_object(res_model, res_id, token='', token_field=''):
|
||||
record = request.env[res_model].browse(res_id).sudo()
|
||||
if token and record and getattr(record, token_field, None) and consteq(getattr(record, token_field), token):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', nosubscribe=True, **kw):
|
||||
""" Generic chatter function, allowing to write on *any* object that inherits mail.thread.
|
||||
If a token is specified, all logged in users will be able to write a message regardless
|
||||
of access rights; if the user is the public user, the message will be posted under the name
|
||||
of the partner_id of the object (or the public user if there is no partner_id on the object).
|
||||
|
||||
:param string res_model: model name of the object
|
||||
:param int res_id: id of the object
|
||||
:param string message: content of the message
|
||||
|
||||
optional keywords arguments:
|
||||
:param string token: access token if the object's model uses some kind of public access
|
||||
using tokens (usually a uuid4) to bypass access rules
|
||||
:param string token_field: name of the field that contains the token on the object (defaults to 'token')
|
||||
:param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True)
|
||||
|
||||
The rest of the kwargs are passed on to message_post()
|
||||
"""
|
||||
record = request.env[res_model].browse(res_id)
|
||||
author_id = request.env.user.partner_id.id if request.env.user.partner_id else False
|
||||
if token_field and token:
|
||||
access_as_sudo = _special_access_object(res_model, res_id, token=token, token_field=token_field)
|
||||
if access_as_sudo:
|
||||
record = record.sudo()
|
||||
if request.env.user == request.env.ref('base.public_user'):
|
||||
author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id
|
||||
else:
|
||||
if not author_id:
|
||||
raise NotFound()
|
||||
else:
|
||||
raise Forbidden()
|
||||
kw.pop('csrf_token', None)
|
||||
return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message,
|
||||
message_type=kw.pop('message_type', "comment"),
|
||||
subtype=kw.pop('subtype', "mt_comment"),
|
||||
author_id=author_id,
|
||||
**kw)
|
||||
|
||||
|
||||
class PortalChatter(http.Controller):
|
||||
|
||||
@http.route(['/mail/chatter_post'], type='http', methods=['POST'], auth='public', website=True)
|
||||
def portal_chatter_post(self, res_model, res_id, message, **kw):
|
||||
url = request.httprequest.referrer
|
||||
if message:
|
||||
_message_post_helper(res_model, int(res_id), message, **kw)
|
||||
url = url + "#discussion"
|
||||
return request.redirect(url)
|
||||
|
||||
@http.route('/mail/chatter_init', type='json', auth='public', website=True)
|
||||
def portal_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
|
||||
is_user_public = request.env.user.has_group('base.group_public')
|
||||
message_data = self.portal_message_fetch(res_model, res_id, domain=domain, limit=limit, **kwargs)
|
||||
display_composer = False
|
||||
if kwargs.get('allow_composer'):
|
||||
display_composer = kwargs.get('token') or not is_user_public
|
||||
return {
|
||||
'messages': message_data['messages'],
|
||||
'options': {
|
||||
'message_count': message_data['message_count'],
|
||||
'is_user_public': is_user_public,
|
||||
'is_user_publisher': request.env.user.has_group('website.group_website_publisher'),
|
||||
'display_composer': display_composer,
|
||||
'partner_id': request.env.user.partner_id.id
|
||||
}
|
||||
}
|
||||
|
||||
@http.route('/mail/chatter_fetch', type='json', auth='public', website=True)
|
||||
def portal_message_fetch(self, res_model, res_id, domain=False, limit=10, offset=0, **kw):
|
||||
if not domain:
|
||||
domain = []
|
||||
# Only search into website_message_ids, so apply the same domain to perform only one search
|
||||
# extract domain from the 'website_message_ids' field
|
||||
field_domain = request.env[res_model]._fields['website_message_ids'].domain
|
||||
domain += field_domain(request.env[res_model]) if callable(field_domain) else field_domain
|
||||
domain += [('res_id', '=', res_id)]
|
||||
# Check access
|
||||
Message = request.env['mail.message']
|
||||
if kw.get('token'):
|
||||
access_as_sudo = _special_access_object(res_model, res_id, token=kw.get('token'), token_field=kw.get('token_field'))
|
||||
if not access_as_sudo: # if token is not correct, raise Forbidden
|
||||
raise Forbidden()
|
||||
Message = request.env['mail.message'].sudo()
|
||||
return {
|
||||
'messages': Message.search(domain, limit=limit, offset=offset).portal_message_format(),
|
||||
'message_count': Message.search_count(domain)
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import portal_mixin
|
||||
from . import mail_thread
|
||||
from . import mail_message
|
||||
from . import portal_mixin
|
||||
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class MailMessage(models.Model):
|
||||
_inherit = 'mail.message'
|
||||
|
||||
@api.multi
|
||||
def portal_message_format(self):
|
||||
return self._portal_message_format([
|
||||
'id', 'body', 'date', 'author_id', 'email_from', # base message fields
|
||||
'message_type', 'subtype_id', 'subject', # message specific
|
||||
'model', 'res_id', 'record_name', # document related
|
||||
])
|
||||
|
||||
@api.multi
|
||||
def _portal_message_format(self, fields_list):
|
||||
message_values = self.read(fields_list)
|
||||
message_tree = dict((m.id, m) for m in self.sudo())
|
||||
self._message_read_dict_postprocess(message_values, message_tree)
|
||||
return message_values
|
||||
@@ -0,0 +1,238 @@
|
||||
odoo.define('portal.chatter', function(require) {
|
||||
'use strict';
|
||||
|
||||
var base = require('web_editor.base');
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
var rpc = require('web.rpc');
|
||||
|
||||
var qweb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
/**
|
||||
* Widget PortalChatter
|
||||
*
|
||||
* - Fetch message fron controller
|
||||
* - Display chatter: pager, total message, composer (according to access right)
|
||||
* - Provider API to filter displayed messages
|
||||
*/
|
||||
var PortalChatter = Widget.extend({
|
||||
template: 'portal.chatter',
|
||||
events: {
|
||||
"click .o_portal_chatter_pager_btn": '_onClickPager'
|
||||
},
|
||||
|
||||
init: function(parent, options){
|
||||
this._super.apply(this, arguments);
|
||||
this.options = _.defaults(options || {}, {
|
||||
'allow_composer': true,
|
||||
'display_composer': false,
|
||||
'csrf_token': odoo.csrf_token,
|
||||
'message_count': 0,
|
||||
'pager_step': 10,
|
||||
'pager_scope': 5,
|
||||
'pager_start': 1,
|
||||
'is_user_public': true,
|
||||
'is_user_publisher': false,
|
||||
'domain': [],
|
||||
});
|
||||
this.set('messages', []);
|
||||
this.set('message_count', this.options['message_count']);
|
||||
this.set('pager', {});
|
||||
this.set('domain', this.options['domain']);
|
||||
this._current_page = this.options['pager_start'];
|
||||
},
|
||||
willStart: function(){
|
||||
var self = this;
|
||||
// load qweb template and init data
|
||||
return $.when(
|
||||
rpc.query({
|
||||
route: '/mail/chatter_init',
|
||||
params: this._messageFetchPrepareParams()
|
||||
}), this._loadTemplates()
|
||||
).then(function(result){
|
||||
// bind events
|
||||
self.on("change:messages", self, self._renderMessages);
|
||||
self.on("change:message_count", self, function(){
|
||||
self._renderMessageCount();
|
||||
self.set('pager', self._pager(self._current_page));
|
||||
});
|
||||
self.on("change:pager", self, self._renderPager);
|
||||
self.on("change:domain", self, self._onChangeDomain);
|
||||
// set options and parameters
|
||||
self.options = _.extend(self.options, result['options'] || {});
|
||||
self.set('message_count', self.options['message_count']);
|
||||
self.set('messages', self.preprocessMessages(result['messages']));
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch the messages and the message count from the server for the
|
||||
* current page and current domain.
|
||||
*
|
||||
* @param {Array}
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
messageFetch: function(domain){
|
||||
var self = this;
|
||||
return rpc.query({
|
||||
route: '/mail/chatter_fetch',
|
||||
params: self._messageFetchPrepareParams()
|
||||
}).then(function(result){
|
||||
self.set('messages', self.preprocessMessages(result['messages']));
|
||||
self.set('message_count', result['message_count']);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Update the messages format
|
||||
*
|
||||
* @param {Array<Object>}
|
||||
* @returns {Array}
|
||||
*/
|
||||
preprocessMessages: function(messages){
|
||||
_.each(messages, function(m){
|
||||
m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
|
||||
m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a'));
|
||||
});
|
||||
return messages;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Change the current page by refreshing current domain
|
||||
*
|
||||
* @private
|
||||
* @param {Number} page
|
||||
* @param {Array} domain
|
||||
*/
|
||||
_changeCurrentPage: function(page, domain){
|
||||
this._current_page = page;
|
||||
var d = domain ? domain : _.clone(this.get('domain'));
|
||||
this.set('domain', d); // trigger fetch message
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_loadTemplates: function(){
|
||||
return ajax.loadXML('/portal/static/src/xml/portal_chatter.xml', qweb);
|
||||
},
|
||||
_messageFetchPrepareParams: function(){
|
||||
var self = this;
|
||||
var data = {
|
||||
'res_model': this.options['res_model'],
|
||||
'res_id': this.options['res_id'],
|
||||
'limit': this.options['pager_step'],
|
||||
'offset': (this._current_page-1) * this.options['pager_step'],
|
||||
'allow_composer': this.options['allow_composer'],
|
||||
};
|
||||
// add fields to allow to post comment without being logged
|
||||
_.each(['token', 'token_field'], function(field){
|
||||
if(self.options[field]){
|
||||
data[field] = self.options[field];
|
||||
}
|
||||
});
|
||||
// add domain
|
||||
if(this.get('domain')){
|
||||
data['domain'] = this.get('domain');
|
||||
}
|
||||
return data;
|
||||
},
|
||||
/**
|
||||
* Generate the pager data for the given page number
|
||||
*
|
||||
* @private
|
||||
* @param {Number} page
|
||||
* @returns {Object}
|
||||
*/
|
||||
_pager: function(page){
|
||||
var page = page || 1;
|
||||
var total = this.get('message_count');
|
||||
var scope = this.options['pager_scope'];
|
||||
var step = this.options['pager_step'];
|
||||
|
||||
// Compute Pager
|
||||
var page_count = Math.ceil(parseFloat(total) / step);
|
||||
|
||||
var page = Math.max(1, Math.min(parseInt(page), page_count));
|
||||
scope -= 1;
|
||||
|
||||
var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
|
||||
var pmax = Math.min(pmin + scope, page_count);
|
||||
|
||||
if(pmax - scope > 0){
|
||||
pmin = pmax - scope;
|
||||
}else{
|
||||
pmin = 1;
|
||||
}
|
||||
|
||||
var pages = [];
|
||||
_.each(_.range(pmin, pmax+1), function(index){
|
||||
pages.push(index);
|
||||
});
|
||||
|
||||
return {
|
||||
"page_count": page_count,
|
||||
"offset": (page - 1) * step,
|
||||
"page": page,
|
||||
"page_start": pmin,
|
||||
"page_previous": Math.max(pmin, page - 1),
|
||||
"page_next": Math.min(pmax, page + 1),
|
||||
"page_end": pmax,
|
||||
"pages": pages
|
||||
};
|
||||
},
|
||||
_renderMessages: function(){
|
||||
this.$('.o_portal_chatter_messages').html(qweb.render("portal.chatter_messages", {widget: this}));
|
||||
},
|
||||
_renderMessageCount: function(){
|
||||
this.$('.o_message_counter').replaceWith(qweb.render("portal.chatter_message_count", {widget: this}));
|
||||
},
|
||||
_renderPager: function(){
|
||||
this.$('.o_portal_chatter_pager').replaceWith(qweb.render("portal.pager", {widget: this}));
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
_onChangeDomain: function(){
|
||||
var self = this;
|
||||
this.messageFetch().then(function(){
|
||||
var p = self._current_page;
|
||||
self.set('pager', self._pager(p));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onClickPager: function(ev){
|
||||
ev.preventDefault();
|
||||
var page = $(ev.currentTarget).data('page');
|
||||
this._changeCurrentPage(page);
|
||||
},
|
||||
});
|
||||
|
||||
base.ready().then(function () {
|
||||
$('.o_website_mail_thread').each(function (index) {
|
||||
var $elem = $(this);
|
||||
var mail_thread = new WebsiteMailThread(null, $elem.data());
|
||||
mail_thread.appendTo($elem);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
PortalChatter: PortalChatter,
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
.o_portal_chatter {
|
||||
padding: 10px;
|
||||
|
||||
.o_portal_chatter_avatar{
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.o_portal_chatter_header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.o_portal_chatter_composer {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.o_portal_chatter_messages {
|
||||
margin-bottom: 15px;
|
||||
|
||||
.o_portal_chatter_message_title {
|
||||
p {
|
||||
font-size:85%;
|
||||
color:@odoo-main-color-muted;
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_portal_chatter_pager {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="portal.chatter_message_count">
|
||||
<t t-set="count" t-value="widget.get('message_count')"/>
|
||||
<div class="o_message_counter">
|
||||
<t t-if="count">
|
||||
<span class="o_message_count fa fa-comments"> <t t-esc="count"/></span>
|
||||
<t t-if="count == 1">comment</t>
|
||||
<t t-else="">comments</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
There are no comments for now.
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="portal.chatter_composer">
|
||||
<div class="o_portal_chatter_composer" t-if="widget.options['allow_composer']">
|
||||
<t t-if="!widget.options['display_composer']">
|
||||
<h4>Leave a comment</h4>
|
||||
<p>You must be <a t-attf-href="/web/login?redirect=#{window.encodeURI(window.location.href + '#discussion')}">logged in</a> to post a comment.</p>
|
||||
</t>
|
||||
<t t-if="widget.options['display_composer']">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img class="o_portal_chatter_avatar pull-left" t-attf-src="/web/image/res.partner/#{widget.options['partner_id']}/image_small/50x50"/>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<form class="o_portal_chatter_composer_form" t-attf-action="/mail/chatter_post" method="POST">
|
||||
<input type="hidden" name="csrf_token" t-att-value="widget.options['csrf_token']"/>
|
||||
<div class="mb32">
|
||||
<textarea rows="4" name="message" class="form-control" placeholder="Write a message..."></textarea>
|
||||
<input type='hidden' name="res_model" t-att-value="widget.options['res_model']"/>
|
||||
<input type='hidden' name="res_id" t-att-value="widget.options['res_id']"/>
|
||||
<input type='hidden' name="token" t-att-value="widget.options['token']" t-if="widget.options['token']"/>
|
||||
<input type='hidden' name="sha_in" t-att-value="widget.options['sha_in']" t-if="widget.options['sha_in']"/>
|
||||
<input type='hidden' name="sha_time" t-att-value="widget.options['sha_time']" t-if="widget.options['sha_time']"/>
|
||||
<input type='hidden' name="token_field" t-att-value="widget.options['token_field']" t-if="widget.options['token_field']"/>
|
||||
<div class="alert alert-danger mt8 mb0 o_portal_chatter_composer_error" style="display:none;">
|
||||
Oops! Something went wrong. Try to reload the page and log in.
|
||||
</div>
|
||||
<button t-attf-class="o_portal_chatter_composer_btn btn btn-primary mt8 o_website_message_post_helper" type="submit">Send</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<hr/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="portal.chatter_messages">
|
||||
<div class="o_portal_chatter_messages">
|
||||
<t t-foreach="widget.get('messages')" t-as="message">
|
||||
<div class="media o_portal_chatter_message" t-att-id="'message-' + message.id">
|
||||
<div class="media-left">
|
||||
<img class="media-object o_portal_chatter_avatar" t-att-src="message.author_avatar_url" alt="avatar"/>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
|
||||
<div class="o_portal_chatter_message_title">
|
||||
<h5 class="media-heading">
|
||||
<t t-esc="message.author_id[1]"/>
|
||||
</h5>
|
||||
<p class="o_portal_chatter_puslished_date"><t t-esc="message.published_date_str"/></p>
|
||||
</div>
|
||||
<t t-raw="message.body"/>
|
||||
|
||||
<div class="o_portal_chatter_attachments">
|
||||
<div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'>
|
||||
<a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank">
|
||||
<div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/>
|
||||
<div class='oe_attachment_name'><t t-raw='attachment.name'/></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="portal.pager">
|
||||
<div class="o_portal_chatter_pager">
|
||||
<t t-if="!_.isEmpty(widget.get('pager'))">
|
||||
<ul class="pagination" t-if="widget.get('pager')['pages'].length > 1">
|
||||
<li t-if="widget.get('pager')['page'] != widget.get('pager')['page_previous']" t-att-data-page="widget.get('pager')['page_previous']" class="o_portal_chatter_pager_btn">
|
||||
<a href="#"><i class="fa fa-chevron-left"/></a>
|
||||
</li>
|
||||
<t t-foreach="widget.get('pager')['pages']" t-as="page">
|
||||
<li t-att-data-page="page" t-att-class="page == widget.get('pager')['page'] ? 'o_portal_chatter_pager_btn active' : 'o_portal_chatter_pager_btn'">
|
||||
<a href="#"><t t-esc="page"/></a>
|
||||
</li>
|
||||
</t>
|
||||
<li t-if="widget.get('pager')['page'] != widget.get('pager')['page_next']" t-att-data-page="widget.get('pager')['page_next']" class="o_portal_chatter_pager_btn">
|
||||
<a href="#"><i class="fa fa-chevron-right"/></a>
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="portal.chatter">
|
||||
<div class="o_portal_chatter">
|
||||
<div class="o_portal_chatter_header">
|
||||
<t t-call="portal.chatter_message_count"/>
|
||||
</div>
|
||||
<hr/>
|
||||
<t t-call="portal.chatter_composer"/>
|
||||
<t t-call="portal.chatter_messages"/>
|
||||
<div class="o_portal_chatter_footer">
|
||||
<t t-call="portal.pager"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -5,10 +5,12 @@
|
||||
<link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.ui.less"/>
|
||||
<link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.wrapwrap.less"/>
|
||||
<link rel="stylesheet" type="text/less" href="/portal/static/src/less/bootstrap.extend.less"/>
|
||||
<link rel="stylesheet" type="text/less" href="/portal/static/src/less/portal_chatter.less"/>
|
||||
</xpath>
|
||||
<xpath expr="//script[last()]" position="after">
|
||||
<script type="text/javascript" src="/portal/static/src/js/portal.js"></script>
|
||||
<script type="text/javascript" src="/portal/static/src/js/portal_tour.js"></script>
|
||||
<script type="text/javascript" src="/portal/static/src/js/portal_chatter.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -336,4 +336,22 @@
|
||||
<li><a href="/my/home" role="menuitem">My Account</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
Generic chatter template for the frontend
|
||||
This template provide the container of the chatter. The rest is done in js.
|
||||
To use this template, you need to call it after setting the following variable in your template or in your controller:
|
||||
:object browserecord : the mail_thread object
|
||||
:message_per_page int (optional): number of message per chatter page
|
||||
:token string (optional): if you want your chatter to be available for non-logged user,
|
||||
you can use a token to verify the identity of the user;
|
||||
the message will be posted with the identity of the partner_id of the object
|
||||
:token_field string (optional): name of the field that contains the token on the object (default to 'token')
|
||||
-->
|
||||
<template id="message_thread">
|
||||
<div id="discussion" class="hidden-print o_portal_chatter"
|
||||
t-att-data-token="token" t-att-data-res_model="object._name" t-att-data-res_id="object.id" t-att-data-token_field="token_field" t-att-data-pager_step="message_per_page or 10" t-att-data-allow_composer="'0' if disable_composer else '1'">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import report
|
||||
from . import wizard
|
||||
@@ -13,6 +13,7 @@
|
||||
'product',
|
||||
'analytic',
|
||||
'mail',
|
||||
'portal',
|
||||
'resource',
|
||||
'web',
|
||||
'web_planner',
|
||||
@@ -28,6 +29,7 @@
|
||||
'views/res_partner_views.xml',
|
||||
'views/project_config_settings_views.xml',
|
||||
'views/project_templates.xml',
|
||||
'views/project_portal_templates.xml',
|
||||
'data/web_planner_data.xml',
|
||||
'data/project_mail_template_data.xml',
|
||||
'wizard/project_task_merge_wizard_views.xml',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import main
|
||||
from . import portal
|
||||
@@ -5,15 +5,16 @@ from collections import OrderedDict
|
||||
|
||||
from odoo import http, _
|
||||
from odoo.http import request
|
||||
from odoo.addons.portal.controllers.portal import get_records_pager, CustomerPortal
|
||||
from odoo.addons.portal.controllers.portal import get_records_pager, CustomerPortal, pager as portal_pager
|
||||
|
||||
from odoo.osv.expression import OR
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class WebsiteAccount(CustomerPortal):
|
||||
class CustomerPortal(CustomerPortal):
|
||||
|
||||
def _prepare_portal_layout_values(self):
|
||||
values = super(WebsiteAccount, self)._prepare_portal_layout_values()
|
||||
values = super(CustomerPortal, self)._prepare_portal_layout_values()
|
||||
values.update({
|
||||
'project_count': request.env['project.project'].search_count([('privacy_visibility', '=', 'portal')]),
|
||||
'task_count': request.env['project.task'].search_count([('project_id.privacy_visibility', '=', 'portal')])
|
||||
@@ -21,7 +22,7 @@ class WebsiteAccount(CustomerPortal):
|
||||
return values
|
||||
|
||||
@http.route(['/my/projects', '/my/projects/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def my_projects(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
|
||||
def portal_my_projects(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
|
||||
values = self._prepare_portal_layout_values()
|
||||
Project = request.env['project.project']
|
||||
domain = [('privacy_visibility', '=', 'portal')]
|
||||
@@ -41,7 +42,7 @@ class WebsiteAccount(CustomerPortal):
|
||||
# projects count
|
||||
project_count = Project.search_count(domain)
|
||||
# pager
|
||||
pager = request.website.pager(
|
||||
pager = portal_pager(
|
||||
url="/my/projects",
|
||||
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
|
||||
total=project_count,
|
||||
@@ -64,17 +65,18 @@ class WebsiteAccount(CustomerPortal):
|
||||
'searchbar_sortings': searchbar_sortings,
|
||||
'sortby': sortby
|
||||
})
|
||||
return request.render("website_project.my_projects", values)
|
||||
return request.render("project.portal_my_projects", values)
|
||||
|
||||
@http.route(['/my/project/<model("project.project"):project>'], type='http', auth="user", website=True)
|
||||
def my_project(self, project=None, **kw):
|
||||
vals = {'project': project, }
|
||||
@http.route(['/my/project/<int:project_id>'], type='http', auth="user", website=True)
|
||||
def portal_my_project(self, project_id=None, **kw):
|
||||
project = request.env['project.project'].browse(project_id)
|
||||
vals = {'project': project}
|
||||
history = request.session.get('my_projects_history', [])
|
||||
vals.update(get_records_pager(history, project))
|
||||
return request.render("website_project.my_project", vals)
|
||||
return request.render("project.portal_my_project", vals)
|
||||
|
||||
@http.route(['/my/tasks', '/my/tasks/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw):
|
||||
def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw):
|
||||
values = self._prepare_portal_layout_values()
|
||||
domain = [('project_id.privacy_visibility', '=', 'portal')]
|
||||
|
||||
@@ -131,7 +133,7 @@ class WebsiteAccount(CustomerPortal):
|
||||
# task count
|
||||
task_count = request.env['project.task'].search_count(domain)
|
||||
# pager
|
||||
pager = request.website.pager(
|
||||
pager = portal_pager(
|
||||
url="/my/tasks",
|
||||
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby, 'filterby': filterby},
|
||||
total=task_count,
|
||||
@@ -158,11 +160,15 @@ class WebsiteAccount(CustomerPortal):
|
||||
'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))),
|
||||
'filterby': filterby,
|
||||
})
|
||||
return request.render("website_project.my_tasks", values)
|
||||
return request.render("project.portal_my_tasks", values)
|
||||
|
||||
@http.route(['/my/task/<model("project.task"):task>'], type='http', auth="user", website=True)
|
||||
def my_task(self, task=None, **kw):
|
||||
vals = {'task': task, 'user': request.env.user}
|
||||
@http.route(['/my/task/<int:task_id>'], type='http', auth="user", website=True)
|
||||
def portal_my_task(self, task_id=None, **kw):
|
||||
task = request.env['project.task'].browse(task_id)
|
||||
vals = {
|
||||
'task': task,
|
||||
'user': request.env.user
|
||||
}
|
||||
history = request.session.get('my_tasks_history', [])
|
||||
vals.update(get_records_pager(history, task))
|
||||
return request.render("website_project.my_task", vals)
|
||||
return request.render("project.portal_my_task", vals)
|
||||
@@ -67,6 +67,8 @@
|
||||
<field name="color">3</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="type_ids" eval="[(4, ref('project_stage_0')), (4, ref('project_stage_1')), (4, ref('project_stage_2')), (4, ref('project_stage_3'))]"/>
|
||||
<field name="partner_id" ref="base.partner_demo_portal"/>
|
||||
<field name="privacy_visibility">portal</field>
|
||||
</record>
|
||||
|
||||
<record id="project_project_2" model="project.project">
|
||||
@@ -425,5 +427,8 @@ Send it ASAP, its urgent.</field>
|
||||
<field name="author_id" ref="base.partner_root"/>
|
||||
</record>
|
||||
|
||||
<function model="project.project" name="message_subscribe"
|
||||
eval="[ref('project.project_project_1')], [ref('base.partner_demo_portal')]"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from lxml import etree
|
||||
|
||||
from odoo import api, fields, models, tools, SUPERUSER_ID, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class ProjectTaskType(models.Model):
|
||||
class Project(models.Model):
|
||||
_name = "project.project"
|
||||
_description = "Project"
|
||||
_inherit = ['mail.alias.mixin', 'mail.thread']
|
||||
_inherit = ['mail.alias.mixin', 'mail.thread', 'portal.mixin']
|
||||
_inherits = {'account.analytic.account': "analytic_account_id"}
|
||||
_order = "sequence, name, id"
|
||||
_period_number = 5
|
||||
@@ -225,6 +225,11 @@ class Project(models.Model):
|
||||
('project_date_greater', 'check(date >= date_start)', 'Error! project start-date must be lower than project end-date.')
|
||||
]
|
||||
|
||||
def _compute_portal_url(self):
|
||||
super(Project, self)._compute_portal_url()
|
||||
for project in self:
|
||||
project.portal_url = '/my/project/%s' % project.id
|
||||
|
||||
@api.multi
|
||||
def map_tasks(self, new_project_id):
|
||||
""" copy and map tasks from old to new project """
|
||||
@@ -271,6 +276,30 @@ class Project(models.Model):
|
||||
project.message_subscribe(project.partner_id.ids)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def get_access_action(self, access_uid=None):
|
||||
""" Instead of the classic form view, redirect to website for portal users
|
||||
that can read the project. """
|
||||
self.ensure_one()
|
||||
user, record = self.env.user, self
|
||||
if access_uid:
|
||||
user = self.env['res.users'].sudo().browse(access_uid)
|
||||
record = self.sudo(user)
|
||||
|
||||
if user.share:
|
||||
try:
|
||||
record.check_access_rule('read')
|
||||
except AccessError:
|
||||
pass
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': '/my/project/%s' % self.id,
|
||||
'target': 'self',
|
||||
'res_id': self.id,
|
||||
}
|
||||
return super(Project, self).get_access_action(access_uid)
|
||||
|
||||
@api.multi
|
||||
def message_subscribe(self, partner_ids=None, channel_ids=None, subtype_ids=None, force=True):
|
||||
""" Subscribe to all existing active tasks when subscribing to a project """
|
||||
@@ -290,6 +319,28 @@ class Project(models.Model):
|
||||
self.mapped('tasks').message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
|
||||
return super(Project, self).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
|
||||
|
||||
@api.multi
|
||||
def _notification_recipients(self, message, groups):
|
||||
groups = super(Project, self)._notification_recipients(message, groups)
|
||||
|
||||
for group_name, group_method, group_data in groups:
|
||||
group_data['has_button_access'] = True
|
||||
|
||||
return groups
|
||||
|
||||
@api.multi
|
||||
def toggle_favorite(self):
|
||||
favorite_projects = not_fav_projects = self.env['project.project'].sudo()
|
||||
for project in self:
|
||||
if self.env.user in project.favorite_user_ids:
|
||||
favorite_projects |= project
|
||||
else:
|
||||
not_fav_projects |= project
|
||||
|
||||
# Project User has no write access for project.
|
||||
not_fav_projects.write({'favorite_user_ids': [(4, self.env.uid)]})
|
||||
favorite_projects.write({'favorite_user_ids': [(3, self.env.uid)]})
|
||||
|
||||
@api.multi
|
||||
def close_dialog(self):
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -299,7 +350,7 @@ class Task(models.Model):
|
||||
_name = "project.task"
|
||||
_description = "Task"
|
||||
_date_name = "date_start"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin']
|
||||
_mail_post_access = 'read'
|
||||
_order = "priority desc, sequence, date_start, name, id"
|
||||
|
||||
@@ -383,7 +434,8 @@ class Task(models.Model):
|
||||
default=lambda self: self.env['res.company']._company_default_get())
|
||||
color = fields.Integer(string='Color Index')
|
||||
user_email = fields.Char(related='user_id.email', string='User Email', readonly=True)
|
||||
attachment_ids = fields.One2many('ir.attachment', 'res_id', domain=lambda self: [('res_model', '=', self._name)], auto_join=True, string='Attachments')
|
||||
attachment_ids = fields.One2many('ir.attachment', compute='_compute_attachment_ids', string="Main Attachments",
|
||||
help="Attachment that don't come from message.")
|
||||
# In the domain of displayed_image_id, we couln't use attachment_ids because a one2many is represented as a list of commands so we used res_model & res_id
|
||||
displayed_image_id = fields.Many2one('ir.attachment', domain="[('res_model', '=', 'project.task'), ('res_id', '=', id), ('mimetype', 'ilike', 'image')]", string='Cover Image')
|
||||
legend_blocked = fields.Char(related='stage_id.legend_blocked', string='Kanban Blocked Explanation', readonly=True)
|
||||
@@ -402,6 +454,12 @@ class Task(models.Model):
|
||||
working_days_open = fields.Float(compute='_compute_elapsed', string='Working days to assign', store=True, group_operator="avg")
|
||||
working_days_close = fields.Float(compute='_compute_elapsed', string='Working days to close', store=True, group_operator="avg")
|
||||
|
||||
def _compute_attachment_ids(self):
|
||||
for task in self:
|
||||
attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids
|
||||
message_attachment_ids = self.mapped('message_ids.attachment_ids').ids # from mail_thread
|
||||
task.attachment_ids = list(set(attachment_ids) - set(message_attachment_ids))
|
||||
|
||||
@api.multi
|
||||
@api.depends('create_date', 'date_end', 'date_assign')
|
||||
def _compute_elapsed(self):
|
||||
@@ -436,6 +494,11 @@ class Task(models.Model):
|
||||
else:
|
||||
task.kanban_state_label = task.legend_done
|
||||
|
||||
def _compute_portal_url(self):
|
||||
super(Task, self)._compute_portal_url()
|
||||
for task in self:
|
||||
task.portal_url = '/my/task/%s' % task.id
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def _onchange_partner_id(self):
|
||||
self.email_from = self.partner_id.email
|
||||
@@ -601,6 +664,30 @@ class Task(models.Model):
|
||||
return {'date_end': fields.Datetime.now()}
|
||||
return {'date_end': False}
|
||||
|
||||
@api.multi
|
||||
def get_access_action(self, access_uid=None):
|
||||
""" Instead of the classic form view, redirect to website for portal users
|
||||
that can read the task. """
|
||||
self.ensure_one()
|
||||
user, record = self.env.user, self
|
||||
if access_uid:
|
||||
user = self.env['res.users'].sudo().browse(access_uid)
|
||||
record = self.sudo(user)
|
||||
|
||||
if user.share:
|
||||
try:
|
||||
record.check_access_rule('read')
|
||||
except AccessError:
|
||||
pass
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': '/my/task/%s' % self.id,
|
||||
'target': 'self',
|
||||
'res_id': self.id,
|
||||
}
|
||||
return super(Task, self).get_access_action(access_uid)
|
||||
|
||||
# ---------------------------------------------------
|
||||
# Mail gateway
|
||||
# ---------------------------------------------------
|
||||
@@ -647,7 +734,11 @@ class Task(models.Model):
|
||||
'actions': project_actions,
|
||||
})
|
||||
|
||||
return [new_group] + groups
|
||||
groups = [new_group] + groups
|
||||
for group_name, group_method, group_data in groups:
|
||||
group_data['has_button_access'] = True
|
||||
|
||||
return groups
|
||||
|
||||
@api.model
|
||||
def message_get_reply_to(self, res_ids, default=None):
|
||||
|
||||
@@ -3,18 +3,23 @@ access_project_project,project.project,model_project_project,project.group_proje
|
||||
access_project_project_manager,project.project,model_project_project,project.group_project_manager,1,1,1,1
|
||||
access_account_analytic_account_user,account.analytic.account,analytic.model_account_analytic_account,project.group_project_user,1,0,0,0
|
||||
access_account_analytic_account_manager,account.analytic.account,analytic.model_account_analytic_account,project.group_project_manager,1,1,1,1
|
||||
access_account_analytic_account_portal,account_analytic_account,analytic.model_account_analytic_account,base.group_portal,1,0,0,0
|
||||
access_project_task_type_user,project.task.type.user,model_project_task_type,base.group_user,1,0,0,0
|
||||
access_project_task_type_project_user,project.task.type.project.user,model_project_task_type,project.group_project_user,1,0,0,0
|
||||
access_project_task_type_manager,project.task.type manager,model_project_task_type,project.group_project_manager,1,1,1,1
|
||||
access_project_task_type_portal,task_type_portal,project.model_project_task_type,base.group_portal,1,0,0,0
|
||||
access_project_task,project.task,model_project_task,project.group_project_user,1,1,1,1
|
||||
access_report_project_task_user,report.project.task.user,model_report_project_task_user,project.group_project_manager,1,1,1,1
|
||||
access_partner_task user,base.res.partner user,base.model_res_partner,project.group_project_user,1,0,0,0
|
||||
access_task_on_partner,project.task on partners,model_project_task,base.group_user,1,0,0,0
|
||||
access_project_on_partner,project.project on partners,model_project_project,base.group_user,1,0,0,0
|
||||
access_task_portal,task_portal,project.model_project_task,base.group_portal,1,0,0,0
|
||||
access_project_user,project.project on partners,model_project_project,base.group_user,1,0,0,0
|
||||
access_project_portal,project_portal,project.model_project_project,base.group_portal,1,0,0,0
|
||||
access_account_analytic_line_project,account.analytic.line project,analytic.model_account_analytic_line,project.group_project_manager,1,1,1,1
|
||||
access_resource_calendar,project.resource_calendar user,resource.model_resource_calendar,project.group_project_user,1,0,0,0
|
||||
access_resource_calendar_attendance,project.resource_calendar_attendance user,resource.model_resource_calendar_attendance,project.group_project_user,1,0,0,0
|
||||
access_resource_calendar_leaves_user,resource.calendar.leaves user,resource.model_resource_calendar_leaves,project.group_project_user,1,1,1,1
|
||||
access_project_tags_all,project.project_tags_all,model_project_tags,,1,0,0,0
|
||||
access_project_tags_manager,project.project_tags_manager,model_project_tags,project.group_project_manager,1,1,1,1
|
||||
access_project_tags_portal,project_tags_portal,project.model_project_tags,base.group_portal,1,0,0,0
|
||||
access_mail_alias,mail.alias,mail.model_mail_alias,project.group_project_manager,1,1,1,1
|
||||
|
||||
|
@@ -96,5 +96,32 @@
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<!-- Portal -->
|
||||
<record id="project_project_rule_portal" model="ir.rule">
|
||||
<field name="name">Project: portal users: portal and following</field>
|
||||
<field name="model_id" ref="project.model_project_project"/>
|
||||
<field name="domain_force">[
|
||||
'&',
|
||||
('privacy_visibility', '=', 'portal'),
|
||||
('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_rule_portal" model="ir.rule">
|
||||
<field name="name">Project/Task: portal users: (portal and following project) or (portal and following task)</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
'&',
|
||||
('project_id.privacy_visibility', '=', 'portal'),
|
||||
('project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
'&',
|
||||
('project_id.privacy_visibility', '=', 'portal'),
|
||||
('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_project_base, test_project_flow, test_access_rights, test_project_ui
|
||||
from . import test_project_base, test_project_flow, test_access_rights, test_project_ui, test_portal
|
||||
|
||||
+8
-8
@@ -32,7 +32,7 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="my_projects" name="My Projects">
|
||||
<template id="portal_my_projects" name="My Projects">
|
||||
<t t-call="portal.portal_layout">
|
||||
<h3>Projects
|
||||
<t t-call="portal.portal_searchbar"/>
|
||||
@@ -66,12 +66,12 @@
|
||||
</table></div>
|
||||
</div>
|
||||
<div t-if="pager" class="o_portal_pager text-center">
|
||||
<t t-call="website.pager"/>
|
||||
<t t-call="portal.pager"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="my_project" name="My Project">
|
||||
<template id="portal_my_project" name="My Project">
|
||||
<t t-call="portal.portal_layout">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -117,7 +117,7 @@
|
||||
<h4><strong>Message and communication history</strong></h4>
|
||||
</div>
|
||||
<div class="col-md-10 col-md-offset-1 mt16">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="project"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -125,7 +125,7 @@
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="my_tasks" name="My Tasks">
|
||||
<template id="portal_my_tasks" name="My Tasks">
|
||||
<t t-call="portal.portal_layout">
|
||||
<h3>Tasks
|
||||
<t t-call="portal.portal_searchbar"/>
|
||||
@@ -158,12 +158,12 @@
|
||||
</table></div>
|
||||
</div>
|
||||
<div t-if="pager" class="o_portal_pager text-center">
|
||||
<t t-call="website.pager"/>
|
||||
<t t-call="portal.pager"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="my_task" name="My Task">
|
||||
<template id="portal_my_task" name="My Task">
|
||||
<t t-call="portal.portal_layout">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -235,7 +235,7 @@
|
||||
<h4><strong>Message and communication history</strong></h4>
|
||||
</div>
|
||||
<div class="col-md-10 col-md-offset-1 mt16">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="task"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -302,7 +302,7 @@
|
||||
<template id="opt_blog_post_complete_comment" name="Allow blog post comment" inherit_id="website_blog.blog_post_complete" active="False" customize_show="True">
|
||||
<xpath expr="//div[hasclass('o_blog_post_complete','o_sharing_links')]" position="after">
|
||||
<section id="comments" class="read_width">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
</t>
|
||||
</section>
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
<h4><strong>Message and communication history</strong></h4>
|
||||
</div>
|
||||
<div class="col-md-10 col-md-offset-1 mt16">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="lead"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -772,7 +772,7 @@
|
||||
<h4><strong>Message and communication history</strong></h4>
|
||||
</div>
|
||||
<div class="col-md-10 col-md-offset-1 mt16">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="opportunity"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
'category': 'Hidden',
|
||||
'summary': 'Website Module for Mail',
|
||||
'version': '0.1',
|
||||
'description': """Glue module holding mail improvements for website.""",
|
||||
'description': """
|
||||
Module holding mail improvements for website.
|
||||
It is responsible of comments moderation for published documents (forum, slides, blog, ...)
|
||||
""",
|
||||
'depends': ['website', 'mail'],
|
||||
'data': [
|
||||
'views/website_mail_templates.xml',
|
||||
|
||||
@@ -1,56 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from werkzeug.exceptions import NotFound, Forbidden
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.tools import consteq
|
||||
|
||||
|
||||
def _special_access_object(res_model, res_id, token='', token_field=''):
|
||||
record = request.env[res_model].browse(res_id).sudo()
|
||||
if token and record and getattr(record, token_field, None) and consteq(getattr(record, token_field), token):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', nosubscribe=True, **kw):
|
||||
""" Generic chatter function, allowing to write on *any* object that inherits mail.thread.
|
||||
If a token is specified, all logged in users will be able to write a message regardless
|
||||
of access rights; if the user is the public user, the message will be posted under the name
|
||||
of the partner_id of the object (or the public user if there is no partner_id on the object).
|
||||
|
||||
:param string res_model: model name of the object
|
||||
:param int res_id: id of the object
|
||||
:param string message: content of the message
|
||||
|
||||
optional keywords arguments:
|
||||
:param string token: access token if the object's model uses some kind of public access
|
||||
using tokens (usually a uuid4) to bypass access rules
|
||||
:param string token_field: name of the field that contains the token on the object (defaults to 'token')
|
||||
:param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True)
|
||||
|
||||
The rest of the kwargs are passed on to message_post()
|
||||
"""
|
||||
record = request.env[res_model].browse(res_id)
|
||||
author_id = request.env.user.partner_id.id if request.env.user.partner_id else False
|
||||
if token_field and token:
|
||||
access_as_sudo = _special_access_object(res_model, res_id, token=token, token_field=token_field)
|
||||
if access_as_sudo:
|
||||
record = record.sudo()
|
||||
if request.env.user == request.env.ref('base.public_user'):
|
||||
author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id
|
||||
else:
|
||||
if not author_id:
|
||||
raise NotFound()
|
||||
else:
|
||||
raise Forbidden()
|
||||
kw.pop('csrf_token', None)
|
||||
return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message,
|
||||
message_type=kw.pop('message_type', "comment"),
|
||||
subtype=kw.pop('subtype', "mt_comment"),
|
||||
author_id=author_id,
|
||||
**kw)
|
||||
|
||||
|
||||
class WebsiteMail(http.Controller):
|
||||
@@ -108,50 +60,3 @@ class WebsiteMail(http.Controller):
|
||||
('partner_id', '=', partner.id)
|
||||
]))
|
||||
return values
|
||||
|
||||
@http.route(['/website_mail/post/post'], type='http', methods=['POST'], auth='public', website=True)
|
||||
def website_chatter_post(self, res_model, res_id, message, **kw):
|
||||
url = request.httprequest.referrer
|
||||
if message:
|
||||
_message_post_helper(res_model, int(res_id), message, **kw)
|
||||
url = url + "#discussion"
|
||||
return request.redirect(url)
|
||||
|
||||
@http.route('/website_mail/init', type='json', auth='public', website=True)
|
||||
def website_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
|
||||
is_user_public = bool(request.env.user == request.website.user_id)
|
||||
message_data = self.website_message_fetch(res_model, res_id, domain=domain, limit=limit, **kwargs)
|
||||
display_composer = False
|
||||
if kwargs.get('allow_composer'):
|
||||
display_composer = kwargs.get('token') or not is_user_public
|
||||
return {
|
||||
'messages': message_data['messages'],
|
||||
'options': {
|
||||
'message_count': message_data['message_count'],
|
||||
'is_user_public': is_user_public,
|
||||
'is_user_publisher': request.env.user.has_group('website.group_website_publisher'),
|
||||
'display_composer': display_composer,
|
||||
'partner_id': request.env.user.partner_id.id
|
||||
}
|
||||
}
|
||||
|
||||
@http.route('/website_mail/fetch', type='json', auth='public', website=True)
|
||||
def website_message_fetch(self, res_model, res_id, domain=False, limit=10, offset=0, **kw):
|
||||
if not domain:
|
||||
domain = []
|
||||
# Only search into website_message_ids, so apply the same domain to perform only one search
|
||||
# extract domain from the 'website_message_ids' field
|
||||
field_domain = request.env[res_model]._fields['website_message_ids'].domain
|
||||
domain += field_domain(request.env[res_model]) if callable(field_domain) else field_domain
|
||||
domain += [('res_id', '=', res_id)]
|
||||
# Check access
|
||||
Message = request.env['mail.message']
|
||||
if kw.get('token'):
|
||||
access_as_sudo = _special_access_object(res_model, res_id, token=kw.get('token'), token_field=kw.get('token_field'))
|
||||
if not access_as_sudo: # if token is not correct, raise Forbidden
|
||||
raise Forbidden()
|
||||
Message = request.env['mail.message'].sudo()
|
||||
return {
|
||||
'messages': Message.search(domain, limit=limit, offset=offset).website_message_format(),
|
||||
'message_count': Message.search_count(domain)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import mail_thread
|
||||
from . import mail_message
|
||||
from . import update
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, SUPERUSER_ID, _
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import html2plaintext
|
||||
from odoo.exceptions import AccessError
|
||||
@@ -58,13 +58,6 @@ class MailMessage(models.Model):
|
||||
return super(MailMessage, self).check_access_rule(operation=operation)
|
||||
|
||||
@api.multi
|
||||
def website_message_format(self):
|
||||
message_values = self.read([
|
||||
'id', 'body', 'date', 'author_id', 'email_from', # base message fields
|
||||
'message_type', 'subtype_id', 'subject', # message specific
|
||||
'model', 'res_id', 'record_name', # document related
|
||||
'website_published',
|
||||
])
|
||||
message_tree = dict((m.id, m) for m in self.sudo())
|
||||
self._message_read_dict_postprocess(message_values, message_tree)
|
||||
return message_values
|
||||
def _portal_message_format(self, fields_list):
|
||||
fields_list += ['website_published']
|
||||
return super(MailMessage, self)._portal_message_format(fields_list)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<record id="mail_message_rule_public" model="ir.rule">
|
||||
<field name="name">mail.message: portal/public: read published messages</field>
|
||||
<field name="model_id" ref="model_mail_message"/>
|
||||
<field name="model_id" ref="mail.model_mail_message"/>
|
||||
<field name="domain_force">[('website_published', '=', True)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
|
||||
</record>
|
||||
|
||||
@@ -2,37 +2,3 @@
|
||||
.js_follow[data-follow='off'] .js_unfollow_btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.o_website_mail_chatter {
|
||||
padding: 10px;
|
||||
|
||||
.o_website_mail_avatar{
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.o_website_mail_header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.o_website_mail_composer {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.o_website_mail_messages {
|
||||
margin-bottom: 15px;
|
||||
|
||||
.o_website_mail_message_title {
|
||||
p {
|
||||
font-size:85%;
|
||||
color:@odoo-main-color-muted;
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.o_website_mail_pager {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,237 +1,20 @@
|
||||
odoo.define('website_mail.thread', function (require) {
|
||||
odoo.define('website_mail.thread', function(require) {
|
||||
'use strict';
|
||||
|
||||
var base = require('web_editor.base');
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
var rpc = require('web.rpc');
|
||||
|
||||
var qweb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
var PortalChatter = require('portal.chatter').PortalChatter;
|
||||
|
||||
/**
|
||||
* Widget WebsiteMailThread
|
||||
*
|
||||
* - Fetch message fron controller
|
||||
* - Display chatter: pager, total message, composer (according to access right)
|
||||
* - Provider API to filter displayed messages
|
||||
* Extends Frontend Chatter to handle rating
|
||||
*/
|
||||
var WebsiteMailThread = Widget.extend({
|
||||
template: 'website_mail.chatter',
|
||||
events: {
|
||||
"click .o_website_mail_pager_btn": '_onClickPager'
|
||||
},
|
||||
|
||||
init: function (parent, options){
|
||||
this._super.apply(this, arguments);
|
||||
this.options = _.defaults(options || {}, {
|
||||
'allow_composer': true,
|
||||
'display_composer': false,
|
||||
'csrf_token': odoo.csrf_token,
|
||||
'message_count': 0,
|
||||
'pager_step': 10,
|
||||
'pager_scope': 5,
|
||||
'pager_start': 1,
|
||||
'is_user_public': true,
|
||||
'is_user_publisher': false,
|
||||
'domain': [],
|
||||
});
|
||||
this.set('messages', []);
|
||||
this.set('message_count', this.options['message_count']);
|
||||
this.set('pager', {});
|
||||
this.set('domain', this.options['domain']);
|
||||
this._current_page = this.options['pager_start'];
|
||||
},
|
||||
willStart: function (){
|
||||
var self = this;
|
||||
// load qweb template and init data
|
||||
return $.when(
|
||||
rpc.query({
|
||||
route: '/website_mail/init',
|
||||
params: this._messageFetchPrepareParams()
|
||||
}), this._loadTemplates()
|
||||
).then(function (result){
|
||||
// bind events
|
||||
self.on("change:messages", self, self._renderMessages);
|
||||
self.on("change:message_count", self, function () {
|
||||
self._renderMessageCount();
|
||||
self.set('pager', self._pager(self._current_page));
|
||||
});
|
||||
self.on("change:pager", self, self._renderPager);
|
||||
self.on("change:domain", self, self._onChangeDomain);
|
||||
// set options and parameters
|
||||
self.options = _.extend(self.options, result['options'] || {});
|
||||
self.set('message_count', self.options['message_count']);
|
||||
self.set('messages', self.preprocessMessages(result['messages']));
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch the messages and the message count from the server for the
|
||||
* current page and current domain.
|
||||
*
|
||||
* @param {Array}
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
messageFetch: function (domain){
|
||||
var self = this;
|
||||
return rpc.query({
|
||||
route: '/website_mail/fetch',
|
||||
params: self._messageFetchPrepareParams()
|
||||
}).then(function (result){
|
||||
self.set('messages', self.preprocessMessages(result['messages']));
|
||||
self.set('message_count', result['message_count']);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Update the messages format
|
||||
*
|
||||
* @param {Array<Object>}
|
||||
* @returns {Array}
|
||||
*/
|
||||
preprocessMessages: function (messages){
|
||||
_.each(messages, function (m){
|
||||
m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
|
||||
m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a'));
|
||||
});
|
||||
return messages;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Change the current page by refreshing current domain
|
||||
*
|
||||
* @private
|
||||
* @param {Number} page
|
||||
* @param {Array} domain
|
||||
*/
|
||||
_changeCurrentPage: function (page, domain){
|
||||
this._current_page = page;
|
||||
var d = domain ? domain : _.clone(this.get('domain'));
|
||||
this.set('domain', d); // trigger fetch message
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_loadTemplates: function () {
|
||||
return ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb);
|
||||
},
|
||||
_messageFetchPrepareParams: function () {
|
||||
var self = this;
|
||||
var data = {
|
||||
'res_model': this.options['res_model'],
|
||||
'res_id': this.options['res_id'],
|
||||
'limit': this.options['pager_step'],
|
||||
'offset': (this._current_page-1) * this.options['pager_step'],
|
||||
'allow_composer': this.options['allow_composer'],
|
||||
};
|
||||
// add fields to allow to post comment without being logged
|
||||
_.each(['token', 'token_field'], function (field) {
|
||||
if (self.options[field]){
|
||||
data[field] = self.options[field];
|
||||
}
|
||||
});
|
||||
// add domain
|
||||
if (this.get('domain')){
|
||||
data['domain'] = this.get('domain');
|
||||
}
|
||||
return data;
|
||||
},
|
||||
/**
|
||||
* Generate the pager data for the given page number
|
||||
*
|
||||
* @private
|
||||
* @param {Number} page
|
||||
* @returns {Object}
|
||||
*/
|
||||
_pager: function (page) {
|
||||
page = page || 1;
|
||||
var total = this.get('message_count');
|
||||
var scope = this.options['pager_scope'];
|
||||
var step = this.options['pager_step'];
|
||||
|
||||
// Compute Pager
|
||||
var page_count = Math.ceil(parseFloat(total) / step);
|
||||
|
||||
page = Math.max(1, Math.min(parseInt(page), page_count));
|
||||
scope -= 1;
|
||||
|
||||
var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
|
||||
var pmax = Math.min(pmin + scope, page_count);
|
||||
|
||||
if (pmax - scope > 0){
|
||||
pmin = pmax - scope;
|
||||
} else {
|
||||
pmin = 1;
|
||||
}
|
||||
|
||||
var pages = [];
|
||||
_.each(_.range(pmin, pmax+1), function (index) {
|
||||
pages.push(index);
|
||||
});
|
||||
|
||||
return {
|
||||
"page_count": page_count,
|
||||
"offset": (page - 1) * step,
|
||||
"page": page,
|
||||
"page_start": pmin,
|
||||
"page_previous": Math.max(pmin, page - 1),
|
||||
"page_next": Math.min(pmax, page + 1),
|
||||
"page_end": pmax,
|
||||
"pages": pages
|
||||
};
|
||||
},
|
||||
_renderMessages: function () {
|
||||
this.$('.o_website_mail_messages').html(qweb.render("website_mail.chatter_messages", {widget: this}));
|
||||
},
|
||||
_renderMessageCount: function () {
|
||||
this.$('.o_message_counter').replaceWith(qweb.render("website_mail.chatter_message_count", {widget: this}));
|
||||
},
|
||||
_renderPager: function () {
|
||||
this.$('.o_website_mail_pager').replaceWith(qweb.render("website_mail.pager", {widget: this}));
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
_onChangeDomain: function () {
|
||||
var self = this;
|
||||
this.messageFetch().then(function () {
|
||||
var p = self.get('current_page');
|
||||
self.set('pager', self._pager(p));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onClickPager: function (ev) {
|
||||
ev.preventDefault();
|
||||
var page = $(ev.currentTarget).data('page');
|
||||
this._changeCurrentPage(page);
|
||||
PortalChatter.include({
|
||||
_loadTemplates: function(){
|
||||
return $.when(this._super(), ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb));
|
||||
},
|
||||
});
|
||||
|
||||
base.ready().then(function () {
|
||||
$('.o_website_mail_thread').each(function (index) {
|
||||
var $elem = $(this);
|
||||
var mail_thread = new WebsiteMailThread(null, $elem.data());
|
||||
mail_thread.appendTo($elem);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
WebsiteMailThread: WebsiteMailThread,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -9,124 +9,15 @@
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="website_mail.chatter_message_count">
|
||||
<t t-set="count" t-value="widget.get('message_count')"/>
|
||||
<div class="o_message_counter">
|
||||
<t t-if="count">
|
||||
<span class="o_message_count fa fa-comments"> <t t-esc="count"/></span>
|
||||
<t t-if="count == 1">comment</t>
|
||||
<t t-else="">comments</t>
|
||||
<t t-extend="portal.chatter_messages">
|
||||
<t t-jquery=".o_portal_chatter_message_title" t-operation="before">
|
||||
<t t-call="website_mail.publish_short">
|
||||
<t t-set="res_model" t-value="'mail.message'"/>
|
||||
<t t-set="res_id" t-value="message.id"/>
|
||||
<t t-set="object" t-value="message"/>
|
||||
<t t-set="is_publisher" t-value="widget.options['is_user_publisher']"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
There are no comments for now.
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="website_mail.chatter_composer">
|
||||
<div class="o_website_mail_composer" t-if="widget.options['allow_composer']">
|
||||
<t t-if="!widget.options['display_composer']">
|
||||
<h4>Leave a comment</h4>
|
||||
<p>You must be <a t-attf-href="/web/login?redirect=#{window.encodeURI(window.location.href + '#discussion')}">logged in</a> to post a comment.</p>
|
||||
</t>
|
||||
<t t-if="widget.options['display_composer']">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img class="o_website_mail_avatar pull-left" t-attf-src="/web/image/res.partner/#{widget.options['partner_id']}/image_small/50x50"/>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<form class="o_website_mail_composer_form" t-attf-action="/website_mail/post/post" method="POST">
|
||||
<input type="hidden" name="csrf_token" t-att-value="widget.options['csrf_token']"/>
|
||||
<div class="mb32">
|
||||
<textarea rows="4" name="message" class="form-control" placeholder="Write a message..."></textarea>
|
||||
<input type='hidden' name="res_model" t-att-value="widget.options['res_model']"/>
|
||||
<input type='hidden' name="res_id" t-att-value="widget.options['res_id']"/>
|
||||
<input type='hidden' name="token" t-att-value="widget.options['token']" t-if="widget.options['token']"/>
|
||||
<input type='hidden' name="sha_in" t-att-value="widget.options['sha_in']" t-if="widget.options['sha_in']"/>
|
||||
<input type='hidden' name="sha_time" t-att-value="widget.options['sha_time']" t-if="widget.options['sha_time']"/>
|
||||
<input type='hidden' name="token_field" t-att-value="widget.options['token_field']" t-if="widget.options['token_field']"/>
|
||||
<div class="alert alert-danger mt8 mb0 o_website_mail_composer_error" style="display:none;">
|
||||
Oops! Something went wrong. Try to reload the page and log in.
|
||||
</div>
|
||||
<button t-attf-class="o_website_mail_composer_btn btn btn-primary mt8 o_website_message_post_helper" type="submit">Send</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<hr/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website_mail.chatter_messages">
|
||||
<div class="o_website_mail_messages">
|
||||
<t t-foreach="widget.get('messages')" t-as="message">
|
||||
<div class="media o_website_mail_message" t-att-id="'message-' + message.id">
|
||||
<div class="media-left">
|
||||
<img class="media-object o_website_mail_avatar" t-att-src="message.author_avatar_url" alt="avatar"/>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
|
||||
<t t-call="website_mail.publish_short">
|
||||
<t t-set="res_model" t-value="'mail.message'"/>
|
||||
<t t-set="res_id" t-value="message.id"/>
|
||||
<t t-set="object" t-value="message"/>
|
||||
<t t-set="is_publisher" t-value="widget.options['is_user_publisher']"/>
|
||||
</t>
|
||||
|
||||
<div class="o_website_mail_message_title">
|
||||
<h5 class="media-heading">
|
||||
<t t-esc="message.author_id[1]"/>
|
||||
</h5>
|
||||
<p class="o_website_mail_puslished_date"><t t-esc="message.published_date_str"/></p>
|
||||
</div>
|
||||
<t t-raw="message.body"/>
|
||||
|
||||
<div class="o_website_mail_attachments">
|
||||
<div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'>
|
||||
<a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank">
|
||||
<div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/>
|
||||
<div class='oe_attachment_name'><t t-raw='attachment.name'/></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website_mail.pager">
|
||||
<div class="o_website_mail_pager">
|
||||
<t t-if="!_.isEmpty(widget.get('pager'))">
|
||||
<ul class="pagination" t-if="widget.get('pager')['pages'].length > 1">
|
||||
<li t-if="widget.get('pager')['page'] != widget.get('pager')['page_previous']" t-att-data-page="widget.get('pager')['page_previous']" class="o_website_mail_pager_btn">
|
||||
<a href="#"><i class="fa fa-chevron-left"/></a>
|
||||
</li>
|
||||
<t t-foreach="widget.get('pager')['pages']" t-as="page">
|
||||
<li t-att-data-page="page" t-att-class="page == widget.get('pager')['page'] ? 'o_website_mail_pager_btn active' : 'o_website_mail_pager_btn'">
|
||||
<a href="#"><t t-esc="page"/></a>
|
||||
</li>
|
||||
</t>
|
||||
<li t-if="widget.get('pager')['page'] != widget.get('pager')['page_next']" t-att-data-page="widget.get('pager')['page_next']" class="o_website_mail_pager_btn">
|
||||
<a href="#"><i class="fa fa-chevron-right"/></a>
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website_mail.chatter">
|
||||
<div class="o_website_mail_chatter">
|
||||
<div class="o_website_mail_header">
|
||||
<t t-call="website_mail.chatter_message_count"/>
|
||||
</div>
|
||||
<hr/>
|
||||
<t t-call="website_mail.chatter_composer"/>
|
||||
<t t-call="website_mail.chatter_messages"/>
|
||||
<div class="o_website_mail_footer">
|
||||
<t t-call="website_mail.pager"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -25,21 +25,4 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
Generic chatter template for the frontend
|
||||
This template provide the container of the chatter. The rest is done in js.
|
||||
To use this template, you need to call it after setting the following variable in your template or in your controller:
|
||||
:object browserecord : the mail_thread object
|
||||
:message_per_page int (optional): number of message per chatter page
|
||||
:token string (optional): if you want your chatter to be available for non-logged user,
|
||||
you can use a token to verify the identity of the user;
|
||||
the message will be posted with the identity of the partner_id of the object
|
||||
:token_field string (optional): name of the field that contains the token on the object (default to 'token')
|
||||
-->
|
||||
<template id="message_thread">
|
||||
<div id="discussion" class="hidden-print o_website_mail_thread"
|
||||
t-att-data-token="token" t-att-public-user="website.env.user == request.website.user_id" t-att-data-res_model="object._name" t-att-data-res_id="object.id" t-att-data-token_field="token_field" t-att-data-pager_step="message_per_page or 10" t-att-data-allow_composer="'0' if disable_composer else '1'">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
@@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name': "Website Project",
|
||||
'description': """
|
||||
Website portal for Project and Tasks
|
||||
====================================
|
||||
""",
|
||||
'category': 'Website',
|
||||
'depends': ['project', 'website', 'portal'],
|
||||
'data': [
|
||||
'security/project_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/project_templates.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/project_demo.xml',
|
||||
],
|
||||
'auto_install': True,
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="project.project_project_1" model="project.project">
|
||||
<field name="partner_id" ref="base.partner_demo_portal"/>
|
||||
<field name="privacy_visibility">portal</field>
|
||||
</record>
|
||||
|
||||
<function model="project.project" name="message_subscribe"
|
||||
eval="[ref('project.project_project_1')], [ref('base.partner_demo_portal')]"/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,189 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# Antonio Trueba <atgayol@gmail.com>, 2016
|
||||
# Roberto Lizana <robertolizana@trey.es>, 2016
|
||||
# José Vicente <txusev@gmail.com>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# oihane <oihanecruce@gmail.com>, 2016
|
||||
# Alejandro Die Sanchis <marketing@domatix.com>, 2016
|
||||
# Gustavo Orozco H. <gustavo.orozco.h@app-247.com>, 2016
|
||||
# José Antonio Cuello <inactive+Yopli2k@transifex.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: José Antonio Cuello <inactive+Yopli2k@transifex.com>, 2017\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>Asignado a</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>Fecha:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>Histórico de mensajes y comunicaciones</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr "<strong>Proyecto:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>Notificado por</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "Todos"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr "Editar Tarea"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "última actualización de la etapa"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "Mis proyectos"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "Mis tareas"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "Más moderno"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "Proyecto"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr "Proyecto -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "Proyectos"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "Etapa"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "Tarea"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "Tareas"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr "Sus Proyectos"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr ""
|
||||
@@ -1,190 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# Xavier Belmere <Info@cartmeleon.com>, 2016
|
||||
# Frédéric LIETART <stuff@tifred.fr>, 2016
|
||||
# Miguel Vidali <mvidali129@gmail.com>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Leo Schmitt <inactive+lschmitt@transifex.com>, 2016
|
||||
# Maxime Chambreuil <mchambreuil@ursainfosystems.com>, 2016
|
||||
# Henri Cornuau <hcornuau@gmail.com>, 2016
|
||||
# Jérémy Donas <LeDistordu@users.noreply.github.com>, 2016
|
||||
# Foo Bar <mat+test@odoo.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Foo Bar <mat+test@odoo.com>, 2017\n"
|
||||
"Language-Team: French (https://www.transifex.com/odoo/teams/41243/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>Assigné à</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr "<strong>Client</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>Date :</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>Historique des messages et communications</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>Rapporté par</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "Tous"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr "Modifié la Tâche"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "Dernière étape de mise à jour"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "Mes projets"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "Mes tâches par zone de temps"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "Le plus récent"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "Projet"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr "Projet -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "Projets"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "Étape"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "Tâche"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "Tâches"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr "Vos projets"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr ""
|
||||
@@ -1,183 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# krnkris <krnkris@freemail.hu>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Martin Trigaux <mat@odoo.com>, 2016\n"
|
||||
"Language-Team: Hungarian (https://www.transifex.com/odoo/teams/41243/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: hu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>Hozzárendelve</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>Dátum:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>Üzenetek és kommunikáció történet</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>Által jelentve</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "Összes"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr "Feladat szerkesztése"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "Utolsó szint frissítése"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "Projekt témáim"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "Feladataim"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "Név"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "Legújabb"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "Projekt téma"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "Projekt témák"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "Értékesítési szint"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "Fladat"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "Feladatok"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr "Projekt témái"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr ""
|
||||
@@ -1,185 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# Yenthe Van Ginneken <yenthespam@gmail.com>, 2016
|
||||
# Cas Vissers <casvissers@brahoo.nl>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Erwin van der Ploeg <erwin@odooexperts.nl>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Erwin van der Ploeg <erwin@odooexperts.nl>, 2016\n"
|
||||
"Language-Team: Dutch (https://www.transifex.com/odoo/teams/41243/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: nl\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>Toegewezen aan</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr "<strong>Klant</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>Datum:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr "<strong>Deadline:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>Berichten en communicatie historie</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr "<strong>Projectleider</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr "<strong>Project:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>Gerapporteerd door</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr "Huidige fase van de taak"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr "Huidige fase van deze taak"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr "Wijzig taak"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "Laatste fase aanpassing"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "Mijn projecten"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "Mijn taken"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "Naam"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "Nieuwste"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "Project"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr "Project -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "Projecten"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "Fase"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "Taak"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr "Taak -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "Taken"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr "Er zijn geen projecten."
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr "Er zijn geen taken."
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr "Uw projecten"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr "Uw taken"
|
||||
@@ -1,187 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# Mateus Lopes <mateus1@gmail.com>, 2016
|
||||
# falexandresilva <falexandresilva@gmail.com>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Peter Leaf <pablleaf@gmail.com>, 2016
|
||||
# grazziano <gra.negocia@gmail.com>, 2016
|
||||
# Anderson Fratuci <ander.frat@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Anderson Fratuci <ander.frat@gmail.com>, 2016\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/odoo/teams/41243/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>Atribuído a</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>Data:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>Histórico de mensagem e comunicação</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>Reportado por</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "Tudo"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "Última Atualização de Estágio"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "Meus Projetos"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "Minhas Tarefas"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "Mais Recente"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "Projeto"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "Projetos"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "Estágio"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "Tarefa"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "Tarefas"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr ""
|
||||
@@ -1,215 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~16\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-07-25 10:04+0000\n"
|
||||
"PO-Revision-Date: 2017-07-25 10:04+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:88
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:85
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:82
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:91
|
||||
#, python-format
|
||||
msgid "Search <span class=\"nolabel\"> (in Content)</span>"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:95
|
||||
#, python-format
|
||||
msgid "Search in All"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:93
|
||||
#, python-format
|
||||
msgid "Search in Customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:92
|
||||
#, python-format
|
||||
msgid "Search in Messages"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:94
|
||||
#, python-format
|
||||
msgid "Search in Stages"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model.fields,help:website_project.field_project_task_website_url
|
||||
msgid "The full URL to access the document through the website."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:83
|
||||
#, python-format
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model.fields,field_description:website_project.field_project_task_website_url
|
||||
msgid "Website URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr ""
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project
|
||||
#
|
||||
# Translators:
|
||||
# Jeffery CHEN <jeffery9@gmail.com>, 2016
|
||||
# Gary Wei <Gary.wei@elico-corp.com>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Talway <9010446@qq.com>, 2016
|
||||
# Luke <cialuo@qq.com>, 2016
|
||||
# 苏州远鼎 <tiexinliu@126.com>, 2016
|
||||
# waveyeung <waveyeung@qq.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: waveyeung <waveyeung@qq.com>, 2016\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Assigned to</strong>"
|
||||
msgstr "<strong>分配给</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Customer</strong>"
|
||||
msgstr "<strong>客户</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Date:</strong>"
|
||||
msgstr "<strong>日期:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Deadline:</strong>"
|
||||
msgstr "<strong>截至日期:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Message and communication history</strong>"
|
||||
msgstr "<strong>消息和交流历史</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "<strong>Project Manager</strong>"
|
||||
msgstr "<strong>项目管理</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Project:</strong>"
|
||||
msgstr "<strong>项目:</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "<strong>Reported by</strong>"
|
||||
msgstr "<strong>汇报</strong>"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:84
|
||||
#, python-format
|
||||
msgid "All"
|
||||
msgstr "All"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Current stage of the task"
|
||||
msgstr "任务的当前阶段"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Current stage of this task"
|
||||
msgstr "任务的当前阶段"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Edit Task"
|
||||
msgstr "编辑任务"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:81
|
||||
#, python-format
|
||||
msgid "Last Stage Update"
|
||||
msgstr "最后阶段更新"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "My Projects"
|
||||
msgstr "我的项目"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "My Tasks"
|
||||
msgstr "我的任务"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:31
|
||||
#: code:addons/website_project/controllers/main.py:79
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#, python-format
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:30
|
||||
#: code:addons/website_project/controllers/main.py:78
|
||||
#, python-format
|
||||
msgid "Newest"
|
||||
msgstr "最新"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_project
|
||||
msgid "Project"
|
||||
msgstr "项目"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_project
|
||||
msgid "Project -"
|
||||
msgstr "项目 -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Projects"
|
||||
msgstr "项目"
|
||||
|
||||
#. module: website_project
|
||||
#: code:addons/website_project/controllers/main.py:80
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#, python-format
|
||||
msgid "Stage"
|
||||
msgstr "阶段"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.model,name:website_project.model_project_task
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "Task"
|
||||
msgstr "任务"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_task
|
||||
msgid "Task -"
|
||||
msgstr "任务 -"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_layout
|
||||
msgid "Tasks"
|
||||
msgstr "任务"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no projects."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "There are currently no quotes."
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
msgid "There are no projects."
|
||||
msgstr "没有项目。"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
msgid "There are no tasks."
|
||||
msgstr "没有任务。"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_projects
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Projects"
|
||||
msgstr "你的项目"
|
||||
|
||||
#. module: website_project
|
||||
#: model:ir.ui.view,arch_db:website_project.my_tasks
|
||||
#: model:ir.ui.view,arch_db:website_project.portal_my_home
|
||||
msgid "Your Tasks"
|
||||
msgstr "你的任务"
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import project
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, exceptions, models, fields
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = ['project.project']
|
||||
|
||||
@api.multi
|
||||
def get_access_action(self, access_uid=None):
|
||||
""" Instead of the classic form view, redirect to website for portal users
|
||||
that can read the project. """
|
||||
self.ensure_one()
|
||||
user, record = self.env.user, self
|
||||
if access_uid:
|
||||
user = self.env['res.users'].sudo().browse(access_uid)
|
||||
record = self.sudo(user)
|
||||
|
||||
if user.share:
|
||||
try:
|
||||
record.check_access_rule('read')
|
||||
except exceptions.AccessError:
|
||||
pass
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': '/my/project/%s' % self.id,
|
||||
'target': 'self',
|
||||
'res_id': self.id,
|
||||
}
|
||||
return super(Project, self).get_access_action(access_uid)
|
||||
|
||||
@api.multi
|
||||
def _notification_recipients(self, message, groups):
|
||||
groups = super(Project, self)._notification_recipients(message, groups)
|
||||
|
||||
for group_name, group_method, group_data in groups:
|
||||
group_data['has_button_access'] = True
|
||||
|
||||
return groups
|
||||
|
||||
|
||||
class Task(models.Model):
|
||||
_inherit = ['project.task']
|
||||
|
||||
website_url = fields.Char('Website URL', compute='_compute_website_url', help='The full URL to access the document through the website.')
|
||||
|
||||
attachment_ids = fields.One2many('ir.attachment', compute='_compute_attachment_ids', string="Main Attachments",
|
||||
help="Attachment that don't come from message.")
|
||||
|
||||
def _compute_attachment_ids(self):
|
||||
for task in self:
|
||||
attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids
|
||||
message_attachment_ids = self.mapped('message_ids.attachment_ids').ids # from mail_thread
|
||||
task.attachment_ids = list(set(attachment_ids) - set(message_attachment_ids))
|
||||
|
||||
def _compute_website_url(self):
|
||||
for task in self:
|
||||
task.website_url = '/my/task/%s' % task.id
|
||||
|
||||
@api.multi
|
||||
def get_access_action(self, access_uid=None):
|
||||
""" Instead of the classic form view, redirect to website for portal users
|
||||
that can read the task. """
|
||||
self.ensure_one()
|
||||
user, record = self.env.user, self
|
||||
if access_uid:
|
||||
user = self.env['res.users'].sudo().browse(access_uid)
|
||||
record = self.sudo(user)
|
||||
|
||||
if user.share:
|
||||
try:
|
||||
record.check_access_rule('read')
|
||||
except exceptions.AccessError:
|
||||
pass
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': self.website_url,
|
||||
'target': 'self',
|
||||
'res_id': self.id,
|
||||
}
|
||||
return super(Task, self).get_access_action(access_uid)
|
||||
|
||||
@api.multi
|
||||
def _notification_recipients(self, message, groups):
|
||||
groups = super(Task, self)._notification_recipients(message, groups)
|
||||
|
||||
for group_name, group_method, group_data in groups:
|
||||
group_data['has_button_access'] = True
|
||||
|
||||
return groups
|
||||
@@ -1,6 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_account_analytic_account_portal,account_analytic_account,analytic.model_account_analytic_account,base.group_portal,1,0,0,0
|
||||
access_project_tags_portal,project_tags_portal,project.model_project_tags,base.group_portal,1,0,0,0
|
||||
access_project_portal,project__portal,project.model_project_project,base.group_portal,1,0,0,0
|
||||
access_task_portal,task_portal,project.model_project_task,base.group_portal,1,0,0,0
|
||||
access_task_type_portal,task_type_portal,project.model_project_task_type,base.group_portal,1,0,0,0
|
||||
|
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Portal -->
|
||||
<record id="portal_project_rule" model="ir.rule">
|
||||
<field name="name">Project: portal users: portal and following</field>
|
||||
<field name="model_id" ref="project.model_project_project"/>
|
||||
<field name="domain_force">[
|
||||
'&',
|
||||
('privacy_visibility', '=', 'portal'),
|
||||
('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="portal_task_rule" model="ir.rule">
|
||||
<field name="name">Project/Task: portal users: (portal and following project) or (portal and following task)</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
'&',
|
||||
('project_id.privacy_visibility', '=', 'portal'),
|
||||
('project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
'&',
|
||||
('project_id.privacy_visibility', '=', 'portal'),
|
||||
('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_access_rights
|
||||
@@ -1,17 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name': 'Timesheet in Website Portal',
|
||||
'category': 'Website',
|
||||
'description': """
|
||||
Display Timesheet on Task in the Website Portal
|
||||
===============================================
|
||||
""",
|
||||
'depends': ['website_project', 'hr_timesheet'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/account_analytic_line_security.xml',
|
||||
'views/account_analytic_line_templates.xml',
|
||||
],
|
||||
'auto_install': True,
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2016
|
||||
# José Vicente <txusev@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: José Vicente <txusev@gmail.com>, 2016\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "Fecha"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "Duración"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "Responsable"
|
||||
@@ -1,42 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Olivier Lenoir <olivier.lenoir@free.fr>, 2016
|
||||
# Fabien Pinckaers <fp@openerp.com>, 2016
|
||||
# Melanie Bernard <mbe@odoo.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Melanie Bernard <mbe@odoo.com>, 2016\n"
|
||||
"Language-Team: French (https://www.transifex.com/odoo/teams/41243/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "Date "
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "Durée"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "Responsable"
|
||||
@@ -1,40 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# krnkris <krnkris@freemail.hu>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: krnkris <krnkris@freemail.hu>, 2016\n"
|
||||
"Language-Team: Hungarian (https://www.transifex.com/odoo/teams/41243/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: hu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "Dátum"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "Leírás"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "Időtartam"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "Felelős"
|
||||
@@ -1,39 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Yenthe Van Ginneken <yenthespam@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Yenthe Van Ginneken <yenthespam@gmail.com>, 2016\n"
|
||||
"Language-Team: Dutch (https://www.transifex.com/odoo/teams/41243/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: nl\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "Omschrijving"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "Tijdsduur"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "Verantwoordelijke"
|
||||
@@ -1,41 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
# Mateus Lopes <mateus1@gmail.com>, 2016
|
||||
# falexandresilva <falexandresilva@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: falexandresilva <falexandresilva@gmail.com>, 2016\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/odoo/teams/41243/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "Data"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "Descrição"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "Duração"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "Responsável"
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr ""
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * website_project_timesheet
|
||||
#
|
||||
# Translators:
|
||||
# Jeffery CHEN <jeffery9@gmail.com>, 2016
|
||||
# Martin Trigaux <mat@odoo.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~14\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-02-15 09:50+0000\n"
|
||||
"PO-Revision-Date: 2017-02-15 09:50+0000\n"
|
||||
"Last-Translator: Martin Trigaux <mat@odoo.com>, 2016\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Date"
|
||||
msgstr "日期"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Description"
|
||||
msgstr "说明"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Duration"
|
||||
msgstr "持续时间"
|
||||
|
||||
#. module: website_project_timesheet
|
||||
#: model:ir.ui.view,arch_db:website_project_timesheet.my_task
|
||||
msgid "Responsible"
|
||||
msgstr "负责人"
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="portal_task_timesheet_rule" model="ir.rule">
|
||||
<field name="name">Project/Task Timesheets: frontend access</field>
|
||||
<field name="model_id" ref="analytic.model_account_analytic_line"/>
|
||||
<field name="domain_force">['|',
|
||||
'&',
|
||||
('task_id.project_id.privacy_visibility', '=', 'portal'),
|
||||
('task_id.project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
'&',
|
||||
('task_id.project_id.privacy_visibility', '=', 'portal'),
|
||||
('task_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,2 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_timesheets_portal,access_timesheets_portal,analytic.model_account_analytic_line,base.group_portal,1,0,0,0
|
||||
|
@@ -6,7 +6,7 @@ import werkzeug
|
||||
from odoo import fields, http, _
|
||||
from odoo.http import request
|
||||
from odoo.addons.portal.controllers.portal import get_records_pager
|
||||
from odoo.addons.website_mail.controllers.main import _message_post_helper
|
||||
from odoo.addons.portal.controllers.mail import _message_post_helper
|
||||
|
||||
|
||||
class sale_quote(http.Controller):
|
||||
|
||||
@@ -430,7 +430,7 @@
|
||||
<xpath expr="//div[@id='quote_content']" position="inside">
|
||||
<h1 class="page-header">History</h1>
|
||||
<!-- Options:Quotation Chatter: user can reply -->
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="quotation"/>
|
||||
<t t-set="token_field" t-value="'access_token'"/>
|
||||
</t>
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.website_mail.controllers.main import WebsiteMail
|
||||
from odoo.addons.portal.controllers.mail import PortalChatter
|
||||
|
||||
|
||||
class WebsiteRating(WebsiteMail):
|
||||
class WebsiteRating(PortalChatter):
|
||||
|
||||
@http.route()
|
||||
def website_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
|
||||
result = super(WebsiteRating, self).website_chatter_init(res_model, res_id, domain=domain, limit=limit, **kwargs)
|
||||
def portal_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
|
||||
result = super(WebsiteRating, self).portal_chatter_init(res_model, res_id, domain=domain, limit=limit, **kwargs)
|
||||
# get the rating statistics about the record
|
||||
if kwargs.get('rating_include'):
|
||||
record = request.env[res_model].browse(res_id)
|
||||
@@ -22,10 +20,10 @@ class WebsiteRating(WebsiteMail):
|
||||
return result
|
||||
|
||||
@http.route()
|
||||
def website_message_fetch(self, res_model, res_id, domain=False, limit=False, offset=False, **kw):
|
||||
# add 'rating_include' in context, to fetch them in website_message_format
|
||||
def portal_message_fetch(self, res_model, res_id, domain=False, limit=False, offset=False, **kw):
|
||||
# add 'rating_include' in context, to fetch them in portal_message_format
|
||||
if kw.get('rating_include'):
|
||||
context = dict(request.context)
|
||||
context['rating_include'] = True
|
||||
request.context = context
|
||||
return super(WebsiteRating, self).website_message_fetch(res_model, res_id, domain=domain, limit=limit, offset=offset, **kw)
|
||||
return super(WebsiteRating, self).portal_message_fetch(res_model, res_id, domain=domain, limit=limit, offset=offset, **kw)
|
||||
|
||||
@@ -8,12 +8,8 @@ class MailMessage(models.Model):
|
||||
_inherit = 'mail.message'
|
||||
|
||||
@api.multi
|
||||
def website_message_format(self):
|
||||
result = super(MailMessage, self).website_message_format()
|
||||
def _portal_message_format(self, field_list):
|
||||
# inlude rating value in data if requested
|
||||
if self._context.get('rating_include'):
|
||||
message_data = self.read(['rating_value'])
|
||||
message_tree = dict((m['id'], m['rating_value']) for m in message_data)
|
||||
for message_vals in result:
|
||||
message_vals['rating_value'] = message_tree.get(message_vals['id'], False) # False for no rating
|
||||
return result
|
||||
field_list += ['rating_value']
|
||||
return super(MailMessage, self)._portal_message_format(field_list)
|
||||
|
||||
@@ -8,13 +8,13 @@ odoo.define('website_rating.thread', function(require) {
|
||||
var qweb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
var WebsiteMailThread = require('website_mail.thread').WebsiteMailThread;
|
||||
var PortalChatter = require('portal.chatter').PortalChatter;
|
||||
|
||||
/**
|
||||
* Extends Frontend Chatter to handle rating
|
||||
*/
|
||||
WebsiteMailThread.include({
|
||||
events: _.extend({}, WebsiteMailThread.prototype.events, {
|
||||
PortalChatter.include({
|
||||
events: _.extend({}, PortalChatter.prototype.events, {
|
||||
"mousemove .stars i" : "_onMoveStar",
|
||||
"mouseleave .stars i" : "_onMoveOutStar",
|
||||
"click .stars" : "_onClickStar",
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<t t-call="website_rating.rating_stars_static">
|
||||
<t t-set="val" t-value="widget.get('rating_card_values')['avg'] || 0"/>
|
||||
</t>
|
||||
<t t-call="website_mail.chatter_message_count"/>
|
||||
<t t-call="portal.chatter_message_count"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6" t-if="!_.isEmpty(widget.get('rating_card_values'))">
|
||||
@@ -76,15 +76,15 @@
|
||||
</t>
|
||||
|
||||
<!--
|
||||
Inherited templates from website_mail to custom chatter with rating
|
||||
Inherited templates from portal to custom chatter with rating
|
||||
-->
|
||||
<t t-extend="website_mail.chatter_composer">
|
||||
<t t-jquery=".o_website_mail_composer_form input[name='csrf_token']" t-operation="after">
|
||||
<t t-extend="portal.chatter_composer">
|
||||
<t t-jquery=".o_portal_chatter_composer_form input[name='csrf_token']" t-operation="after">
|
||||
<t t-call="website_rating.rating_star_input"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="website_mail.chatter_messages">
|
||||
<t t-extend="portal.chatter_messages">
|
||||
<t t-jquery="t[t-raw='message.body']" t-operation="before">
|
||||
<t t-if="message['rating_value']">
|
||||
<t t-call="website_rating.rating_stars_static">
|
||||
@@ -94,13 +94,13 @@
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="website_mail.chatter">
|
||||
<t t-jquery="t[t-call='website_mail.chatter_message_count']" t-operation="replace">
|
||||
<t t-extend="portal.chatter">
|
||||
<t t-jquery="t[t-call='portal.chatter_message_count']" t-operation="replace">
|
||||
<t t-if="widget.options['display_rating']">
|
||||
<t t-call="website_rating.rating_card"/>
|
||||
</t>
|
||||
<t t-if="!widget.options['display_rating']">
|
||||
<t t-call="website_mail.chatter_message_count"/>
|
||||
<t t-call="portal.chatter_message_count"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="message_thread" inherit_id="website_mail.message_thread">
|
||||
<template id="message_thread" inherit_id="portal.message_thread">
|
||||
<xpath expr="//div[@id='discussion']" position="attributes">
|
||||
<attribute name="t-att-data-display_rating">display_rating or False</attribute>
|
||||
</xpath>
|
||||
|
||||
@@ -10,8 +10,8 @@ This module display project customer satisfaction on your website.
|
||||
==================================================================
|
||||
""",
|
||||
'depends': [
|
||||
'website_project',
|
||||
'rating_project'
|
||||
'website',
|
||||
'rating_project',
|
||||
],
|
||||
'data': [
|
||||
'views/website_rating_project.xml',
|
||||
|
||||
@@ -13,7 +13,7 @@ class WebsiteRatingProject(http.Controller):
|
||||
|
||||
@http.route(['/project/rating/'], type='http', auth="public", website=True)
|
||||
def index(self, **kw):
|
||||
projects = request.env['project.project'].sudo().search([('rating_status', '!=', 'no'), ('website_published', '=', True)])
|
||||
projects = request.env['project.project'].sudo().search([('rating_status', '!=', 'no'), ('portal_show_rating', '=', True)])
|
||||
values = {'projects': projects}
|
||||
return request.render('website_rating_project.index', values)
|
||||
|
||||
@@ -23,7 +23,7 @@ class WebsiteRatingProject(http.Controller):
|
||||
project = request.env['project.project'].sudo().browse(project_id)
|
||||
# to avoid giving any access rights on projects to the public user, let's use sudo
|
||||
# and check if the user should be able to view the project (project managers only if it's unpublished or has no rating)
|
||||
if not ((project.rating_status!='no') and project.website_published) and not user.sudo(user).has_group('project.group_project_manager'):
|
||||
if not ((project.rating_status!='no') and project.portal_show_rating) and not user.sudo(user).has_group('project.group_project_manager'):
|
||||
raise NotFound()
|
||||
values = {
|
||||
'project': project,
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
|
||||
_name = "project.project"
|
||||
_inherit = ['project.project', 'website.published.mixin']
|
||||
_inherit = ['project.project']
|
||||
|
||||
portal_show_rating = fields.Boolean('Rating visible in Website', copy=False, oldname='website_published')
|
||||
|
||||
@api.multi
|
||||
def action_view_all_rating(self):
|
||||
""" Override this method without calling parent to redirect to rating website project page """
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'name': "Redirect to the Website Projcet Rating Page",
|
||||
'target': 'self',
|
||||
'url': "/project/rating/%s" % (self.id,)
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def _compute_website_url(self):
|
||||
super(Project, self)._compute_website_url()
|
||||
for project in self:
|
||||
project.website_url = "/project/rating/%s" % project.id
|
||||
if self.portal_show_rating:
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'name': "Redirect to the Website Projcet Rating Page",
|
||||
'target': 'self',
|
||||
'url': "/project/rating/%s" % (self.id,)
|
||||
}
|
||||
return super(Project, self).action_view_all_rating()
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="project_project_view_form" model="ir.ui.view">
|
||||
<field name="name">project.project.inherit.form</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="inherit_id" ref="rating_project.view_project_project_rating_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//div[@name="button_box"]/*[1]' position='before'>
|
||||
<button class="oe_stat_button" name="website_publish_button"
|
||||
type="object" icon="fa-globe" attrs="{'invisible': [('rating_status', '=', 'no')]}">
|
||||
<field name="website_published" widget="website_button"/>
|
||||
</button>
|
||||
<xpath expr="//field[@name='rating_status_period']" position="after">
|
||||
<field name="portal_show_rating" attrs="{'invisible': [('rating_status','==','no')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -115,13 +115,6 @@
|
||||
<div class="container oe_website_rating_project">
|
||||
<h1 t-esc="project.name" class="text-center"/>
|
||||
<div class="row mb32">
|
||||
<div id="website_published_button" class="" groups="project.group_project_manager">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="project"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
<t t-set="action" t-value="'project.open_view_project_all'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<t t-set="type" t-value="'Tasks'"/>
|
||||
<t t-set="data" t-value="task_data"/>
|
||||
|
||||
@@ -552,7 +552,7 @@
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="product"/>
|
||||
<t t-set="display_rating" t-value="True"/>
|
||||
</t>
|
||||
|
||||
@@ -543,7 +543,7 @@
|
||||
</h4>
|
||||
</div>
|
||||
<div t-att-class="comments and 'tab-pane fade active in' or 'tab-pane fade'" id="discuss">
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="slide"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user