[MERGE] forward port of branch saas-4 up to revid bb26dea
This commit is contained in:
commit
a756b82372
|
@ -2055,6 +2055,8 @@ class account_tax(osv.osv):
|
|||
amount = amount2
|
||||
child_tax = self._unit_compute(cr, uid, tax.child_ids, amount, product, partner, quantity)
|
||||
res.extend(child_tax)
|
||||
for child in child_tax:
|
||||
amount2 += child.get('amount', 0.0)
|
||||
if tax.child_depend:
|
||||
for r in res:
|
||||
for name in ('base','ref_base'):
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
from openerp.osv import osv, fields
|
||||
from openerp.addons.edi import EDIMixin
|
||||
|
||||
from urllib import urlencode
|
||||
from werkzeug import url_encode
|
||||
|
||||
INVOICE_LINE_EDI_STRUCT = {
|
||||
'name': True,
|
||||
|
@ -274,7 +274,7 @@ class account_invoice(osv.osv, EDIMixin):
|
|||
"no_note": "1",
|
||||
"bn": "OpenERP_Invoice_PayNow_" + inv.currency_id.name,
|
||||
}
|
||||
res[inv.id] = "https://www.paypal.com/cgi-bin/webscr?" + urlencode(params)
|
||||
res[inv.id] = "https://www.paypal.com/cgi-bin/webscr?" + url_encode(params)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -62,22 +62,28 @@ class account_analytic_invoice_line(osv.osv):
|
|||
context = context or {}
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
company_id = company_id or False
|
||||
context.update({'company_id': company_id, 'force_company': company_id, 'pricelist_id': pricelist_id})
|
||||
local_context = dict(context, company_id=company_id, force_company=company_id, pricelist=pricelist_id)
|
||||
|
||||
if not product:
|
||||
return {'value': {'price_unit': 0.0}, 'domain':{'product_uom':[]}}
|
||||
if partner_id:
|
||||
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=local_context)
|
||||
if part.lang:
|
||||
context.update({'lang': part.lang})
|
||||
|
||||
result = {}
|
||||
res = self.pool.get('product.product').browse(cr, uid, product, context=context)
|
||||
result.update({'name': name or res.description or False,'uom_id': uom_id or res.uom_id.id or False, 'price_unit': price_unit or res.list_price or 0.0})
|
||||
res = self.pool.get('product.product').browse(cr, uid, product, context=local_context)
|
||||
if price_unit is not False:
|
||||
price = price_unit
|
||||
elif pricelist_id:
|
||||
price = res.price
|
||||
else:
|
||||
price = res.list_price
|
||||
result.update({'name': name or res.description or False,'uom_id': uom_id or res.uom_id.id or False, 'price_unit': price})
|
||||
|
||||
res_final = {'value':result}
|
||||
if result['uom_id'] != res.uom_id.id:
|
||||
selected_uom = uom_obj.browse(cr, uid, result['uom_id'], context=context)
|
||||
selected_uom = uom_obj.browse(cr, uid, result['uom_id'], context=local_context)
|
||||
new_price = uom_obj._compute_price(cr, uid, res.uom_id.id, res_final['value']['price_unit'], result['uom_id'])
|
||||
res_final['value']['price_unit'] = new_price
|
||||
return res_final
|
||||
|
|
|
@ -220,7 +220,7 @@ class account_analytic_account(osv.osv):
|
|||
res['value']['description'] = template.description
|
||||
return res
|
||||
|
||||
def on_change_partner_id(self, cr, uid, ids,partner_id, name, context={}):
|
||||
def on_change_partner_id(self, cr, uid, ids,partner_id, name, context=None):
|
||||
res={}
|
||||
if partner_id:
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="provider_openerp" model="auth.oauth.provider">
|
||||
<field name="name">OpenERP.com Accounts</field>
|
||||
<field name="auth_endpoint">https://accounts.openerp.com/oauth2/auth</field>
|
||||
<field name="name">Odoo.com Accounts</field>
|
||||
<field name="auth_endpoint">https://accounts.odoo.com/oauth2/auth</field>
|
||||
<field name="scope">userinfo</field>
|
||||
<field name="validation_endpoint">https://accounts.openerp.com/oauth2/tokeninfo</field>
|
||||
<field name="validation_endpoint">https://accounts.odoo.com/oauth2/tokeninfo</field>
|
||||
<field name="data_endpoint"></field>
|
||||
<field name="css_class">zocial openerp</field>
|
||||
<field name="body">Log in with OpenERP.com</field>
|
||||
<field name="body">Log in with Odoo.com</field>
|
||||
<field name="enabled" eval="True"/>
|
||||
</record>
|
||||
<record id="provider_facebook" model="auth.oauth.provider">
|
||||
|
|
|
@ -170,9 +170,6 @@ class crm_lead(format_address, osv.osv):
|
|||
"""
|
||||
:return dict: difference between current date and log date
|
||||
"""
|
||||
cal_obj = self.pool.get('resource.calendar')
|
||||
res_obj = self.pool.get('resource.resource')
|
||||
|
||||
res = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
for field in fields:
|
||||
|
@ -184,39 +181,14 @@ class crm_lead(format_address, osv.osv):
|
|||
date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
|
||||
date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S")
|
||||
ans = date_open - date_create
|
||||
date_until = lead.date_open
|
||||
elif field == 'day_close':
|
||||
if lead.date_closed:
|
||||
date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
|
||||
date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S")
|
||||
date_until = lead.date_closed
|
||||
ans = date_close - date_create
|
||||
if ans:
|
||||
resource_id = False
|
||||
if lead.user_id:
|
||||
resource_ids = res_obj.search(cr, uid, [('user_id','=',lead.user_id.id)])
|
||||
if len(resource_ids):
|
||||
resource_id = resource_ids[0]
|
||||
|
||||
duration = float(ans.days)
|
||||
if lead.section_id and lead.section_id.resource_calendar_id:
|
||||
duration = float(ans.days) * 24
|
||||
new_dates = cal_obj.interval_get(cr,
|
||||
uid,
|
||||
lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False,
|
||||
datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'),
|
||||
duration,
|
||||
resource=resource_id
|
||||
)
|
||||
no_days = []
|
||||
date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
|
||||
for in_time, out_time in new_dates:
|
||||
if in_time.date not in no_days:
|
||||
no_days.append(in_time.date)
|
||||
if out_time > date_until:
|
||||
break
|
||||
duration = len(no_days)
|
||||
res[lead.id][field] = abs(int(duration))
|
||||
duration = abs(int(ans.days))
|
||||
res[lead.id][field] = duration
|
||||
return res
|
||||
def _meeting_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
Event = self.pool['calendar.event']
|
||||
|
@ -261,7 +233,7 @@ class crm_lead(format_address, osv.osv):
|
|||
'day_open': fields.function(_compute_day, string='Days to Open', \
|
||||
multi='day_open', type="float", store=True),
|
||||
'day_close': fields.function(_compute_day, string='Days to Close', \
|
||||
multi='day_close', type="float", store=True),
|
||||
multi='day_open', type="float", store=True),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
|
||||
|
||||
# Messaging and marketing
|
||||
|
@ -972,7 +944,7 @@ class crm_lead(format_address, osv.osv):
|
|||
if obj.type == 'opportunity':
|
||||
model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
else:
|
||||
view_id = super(crm_lead, self).get_formview_id(cr, uid, id, model='crm.lead', context=context)
|
||||
view_id = super(crm_lead, self).get_formview_id(cr, uid, id, context=context)
|
||||
return view_id
|
||||
|
||||
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -276,7 +276,7 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
|
|||
active_ids = active_ids.difference(merged_lead_ids)
|
||||
active_ids = active_ids.union(remaining_lead_ids)
|
||||
ctx['active_ids'] = list(active_ids)
|
||||
ctx['no_force_assignation'] = not data.force_assignation
|
||||
ctx['no_force_assignation'] = context.get('no_force_assignation', not data.force_assignation)
|
||||
return self.action_apply(cr, uid, ids, context=ctx)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
<field name="computation_mode">count</field>
|
||||
<field name="display_mode">boolean</field>
|
||||
<field name="model_id" eval="ref('base.model_res_company')" />
|
||||
<field name="domain">[('user_ids', 'in', [user.id]), ('name', '=', 'Your Company')]</field>
|
||||
<field name="domain">[('user_ids', 'in', [user.id]), ('name', '=', 'YourCompany')]</field>
|
||||
<field name="condition">lower</field>
|
||||
<field name="action_id" eval="ref('base.action_res_company_form')" />
|
||||
<field name="res_id_field">user.company_id.id</field>
|
||||
|
|
|
@ -316,19 +316,20 @@ class gamification_challenge(osv.Model):
|
|||
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
|
||||
# goals closed but still opened at the last report date
|
||||
closed_goals_to_report = goal_obj.search(cr, uid, [
|
||||
('challenge_id', '=', challenge.id),
|
||||
('start_date', '>=', challenge.last_report_date),
|
||||
('end_date', '<=', challenge.last_report_date)
|
||||
])
|
||||
if challenge.last_report_date != fields.date.today():
|
||||
# goals closed but still opened at the last report date
|
||||
closed_goals_to_report = goal_obj.search(cr, uid, [
|
||||
('challenge_id', '=', challenge.id),
|
||||
('start_date', '>=', challenge.last_report_date),
|
||||
('end_date', '<=', challenge.last_report_date)
|
||||
])
|
||||
|
||||
if len(closed_goals_to_report) > 0:
|
||||
# some goals need a final report
|
||||
self.report_progress(cr, uid, challenge, subset_goal_ids=closed_goals_to_report, context=context)
|
||||
if challenge.next_report_date and fields.date.today() >= challenge.next_report_date:
|
||||
self.report_progress(cr, uid, challenge, context=context)
|
||||
|
||||
if fields.date.today() == challenge.next_report_date:
|
||||
self.report_progress(cr, uid, challenge, context=context)
|
||||
elif len(closed_goals_to_report) > 0:
|
||||
# some goals need a final report
|
||||
self.report_progress(cr, uid, challenge, subset_goal_ids=closed_goals_to_report, context=context)
|
||||
|
||||
self.check_challenge_reward(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
@ -446,6 +447,12 @@ class gamification_challenge(osv.Model):
|
|||
if end_date:
|
||||
values['end_date'] = end_date
|
||||
|
||||
# the goal is initialised over the limit to make sure we will compute it at least once
|
||||
if line.condition == 'higher':
|
||||
values['current'] = line.target_goal - 1
|
||||
else:
|
||||
values['current'] = line.target_goal + 1
|
||||
|
||||
if challenge.remind_update_delay:
|
||||
values['remind_update_delay'] = challenge.remind_update_delay
|
||||
|
||||
|
|
|
@ -349,8 +349,8 @@ class gamification_goal(osv.Model):
|
|||
goal = all_goals[goal_id]
|
||||
|
||||
# check goal target reached
|
||||
if (goal.definition_condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
||||
or (goal.definition_condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
||||
if (goal.definition_id.condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
||||
or (goal.definition_id.condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
||||
value['state'] = 'reached'
|
||||
|
||||
# check goal failure
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</record>
|
||||
|
||||
<record id="goal_global_multicompany" model="ir.rule">
|
||||
<field name="name">User can only see his/her goals or goal from the same challenge in board visibility</field>
|
||||
<field name="name">Multicompany rule on challenges</field>
|
||||
<field name="model_id" ref="model_gamification_goal"/>
|
||||
<field name="domain_force">[('user_id.company_id', 'child_of', [user.company_id.id])]</field>
|
||||
<field name="global" eval="True"/>
|
||||
|
|
|
@ -90,6 +90,11 @@ class hr_holidays_status(osv.osv):
|
|||
}
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
|
||||
if not context.get('employee_id',False):
|
||||
# leave counts is based on employee_id, would be inaccurate if not based on correct employee
|
||||
return super(hr_holidays_status, self).name_get(cr, uid, ids, context=context)
|
||||
|
||||
res = []
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
name = record.name
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('type', '=', 'remove'),('state','!=','draft')]}" string="Mode" groups="base.group_hr_user"/>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('type', '=', 'remove'),('state','!=','draft')]}" string="Mode" groups="base.group_hr_user" context="{'employee_id':employee_id}" />
|
||||
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" on_change="onchange_employee(employee_id)" groups="base.group_hr_user"/>
|
||||
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'readonly': [('type', '=', 'remove'),('state','!=','draft'), ('state','!=','confirm')], 'invisible':[('holiday_type','=','employee')]}"/>
|
||||
<field name="department_id" attrs="{'readonly':['|', ('type','=','add'),('holiday_type','=','category')],'invisible':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
device_list = [
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' },
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0202, 'name' : 'Epson TM-T70' },
|
||||
{ 'vendor' : 0x04b8, 'product' : 0x0e15, 'name' : 'Epson TM-T20II' },
|
||||
]
|
||||
|
||||
|
|
|
@ -176,16 +176,20 @@ class mail_notification(osv.Model):
|
|||
references = message.parent_id.message_id if message.parent_id else False
|
||||
|
||||
# create email values
|
||||
mail_values = {
|
||||
'mail_message_id': message.id,
|
||||
'auto_delete': True,
|
||||
'body_html': body_html,
|
||||
'recipient_ids': [(4, id) for id in email_pids],
|
||||
'references': references,
|
||||
}
|
||||
email_notif_id = self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)
|
||||
if force_send:
|
||||
self.pool.get('mail.mail').send(cr, uid, [email_notif_id], context=context)
|
||||
max_recipients = 100
|
||||
chunks = [email_pids[x:x + max_recipients] for x in xrange(0, len(email_pids), max_recipients)]
|
||||
email_ids = []
|
||||
for chunk in chunks:
|
||||
mail_values = {
|
||||
'mail_message_id': message.id,
|
||||
'auto_delete': True,
|
||||
'body_html': body_html,
|
||||
'recipient_ids': [(4, id) for id in chunk],
|
||||
'references': references,
|
||||
}
|
||||
email_ids.append(self.pool.get('mail.mail').create(cr, uid, mail_values, context=context))
|
||||
if force_send and len(chunks) < 6: # for more than 500 followers, use the queue system
|
||||
self.pool.get('mail.mail').send(cr, uid, email_ids, context=context)
|
||||
return True
|
||||
|
||||
def _notify(self, cr, uid, message_id, partners_to_notify=None, context=None,
|
||||
|
|
|
@ -152,18 +152,8 @@ class mail_mail(osv.Model):
|
|||
context = {}
|
||||
if partner and partner.user_ids:
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
# the parameters to encode for the query and fragment part of url
|
||||
query = {'db': cr.dbname}
|
||||
fragment = {
|
||||
'login': partner.user_ids[0].login,
|
||||
'action': 'mail.action_mail_redirect',
|
||||
}
|
||||
if mail.notification:
|
||||
fragment['message_id'] = mail.mail_message_id.id
|
||||
elif mail.model and mail.res_id:
|
||||
fragment.update(model=mail.model, res_id=mail.res_id)
|
||||
|
||||
url = urljoin(base_url, "/web?%s#%s" % (urlencode(query), urlencode(fragment)))
|
||||
mail_model = mail.model or 'mail.thread'
|
||||
url = urljoin(base_url, self.pool[mail_model]._get_access_link(cr, uid, mail, partner, context=context))
|
||||
return _("""<span class='oe_mail_footer_access'><small>about <a style='color:inherit' href="%s">%s %s</a></small></span>""") % (url, context.get('model_name', ''), mail.record_name)
|
||||
else:
|
||||
return None
|
||||
|
|
|
@ -35,6 +35,7 @@ import socket
|
|||
import time
|
||||
import xmlrpclib
|
||||
from email.message import Message
|
||||
from urllib import urlencode
|
||||
|
||||
from openerp import tools
|
||||
from openerp import SUPERUSER_ID
|
||||
|
@ -648,6 +649,20 @@ class mail_thread(osv.AbstractModel):
|
|||
})
|
||||
return action
|
||||
|
||||
def _get_access_link(self, cr, uid, mail, partner, context=None):
|
||||
# the parameters to encode for the query and fragment part of url
|
||||
query = {'db': cr.dbname}
|
||||
fragment = {
|
||||
'login': partner.user_ids[0].login,
|
||||
'action': 'mail.action_mail_redirect',
|
||||
}
|
||||
if mail.notification:
|
||||
fragment['message_id'] = mail.mail_message_id.id
|
||||
elif mail.model and mail.res_id:
|
||||
fragment.update(model=mail.model, res_id=mail.res_id)
|
||||
|
||||
return "/web?%s#%s" % (urlencode(query), urlencode(fragment))
|
||||
|
||||
#------------------------------------------------------
|
||||
# Email specific
|
||||
#------------------------------------------------------
|
||||
|
|
|
@ -502,11 +502,9 @@ class marketing_campaign_activity(osv.osv):
|
|||
active_ids=[workitem.res_id],
|
||||
active_model=workitem.object_id.model,
|
||||
workitem=workitem)
|
||||
res = server_obj.run(cr, uid, [activity.server_action_id.id],
|
||||
server_obj.run(cr, uid, [activity.server_action_id.id],
|
||||
context=action_context)
|
||||
# server action return False if the action is performed
|
||||
# except client_action, other and python code
|
||||
return res == False and True or res
|
||||
return True
|
||||
|
||||
def process(self, cr, uid, act_id, wi_id, context=None):
|
||||
activity = self.browse(cr, uid, act_id, context=context)
|
||||
|
|
|
@ -21,12 +21,11 @@
|
|||
</group>
|
||||
<group>
|
||||
<div class="oe_right oe_button_box" name="buttons">
|
||||
<button string="Edit Template" name="action_edit_html" type="object"/>
|
||||
<button name="%(email_template.wizard_email_template_preview)d" string="Preview"
|
||||
type="action" target="new"
|
||||
context="{'template_id':active_id}"/>
|
||||
<br />
|
||||
<!-- <field name="website_link" widget='html' radonly='1'
|
||||
style='margin: 0px; padding: 0px;'/> -->
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
|
|
|
@ -580,7 +580,7 @@ class pos_order(osv.osv):
|
|||
try:
|
||||
self.signal_paid(cr, uid, [order_id])
|
||||
except Exception as e:
|
||||
_logger.error('Could not mark POS Order as Paid: %s', tools.ustr(e))
|
||||
_logger.error('Could not fully process the POS Order: %s', tools.ustr(e))
|
||||
|
||||
if to_invoice:
|
||||
self.action_invoice(cr, uid, [order_id], context)
|
||||
|
@ -744,8 +744,6 @@ class pos_order(osv.osv):
|
|||
move_obj = self.pool.get('stock.move')
|
||||
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if not order.state=='draft':
|
||||
continue
|
||||
addr = order.partner_id and partner_obj.address_get(cr, uid, [order.partner_id.id], ['delivery']) or {}
|
||||
picking_type = order.picking_type_id
|
||||
picking_id = False
|
||||
|
|
|
@ -146,6 +146,9 @@ function openerp_pos_db(instance, module){
|
|||
var product = products[i];
|
||||
var search_string = this._product_search_string(product);
|
||||
var categ_id = product.public_categ_id ? product.public_categ_id[0] : this.root_category_id;
|
||||
if (product.variants){
|
||||
product.name = product.name+" ("+product.variants+")";
|
||||
}
|
||||
if(!stored_categories[categ_id]){
|
||||
stored_categories[categ_id] = [];
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
|
||||
return self.fetch(
|
||||
'product.product',
|
||||
['name', 'list_price','price','public_categ_id', 'taxes_id', 'ean13', 'default_code',
|
||||
['name', 'list_price','price','public_categ_id', 'taxes_id', 'ean13', 'default_code', 'variants',
|
||||
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description'],
|
||||
[['sale_ok','=',true],['available_in_pos','=',true]],
|
||||
{pricelist: self.pricelist.id} // context for price
|
||||
|
|
|
@ -895,14 +895,10 @@ class product_product(osv.osv):
|
|||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
context = context or {}
|
||||
default = dict(default or {})
|
||||
if context is None:
|
||||
context={}
|
||||
|
||||
# Craft our own `<name> (copy)` in en_US (self.copy_translation()
|
||||
# will do the other languages).
|
||||
context_wo_lang = dict(context or {})
|
||||
context_wo_lang.pop('lang', None)
|
||||
product = self.browse(cr, uid, id, context_wo_lang)
|
||||
product = self.browse(cr, uid, id, context)
|
||||
if context.get('variant'):
|
||||
# if we copy a variant or create one, we keep the same template
|
||||
default['product_tmpl_id'] = product.product_tmpl_id.id
|
||||
|
|
|
@ -22,7 +22,7 @@ from openerp.osv import osv, fields
|
|||
from openerp.addons.edi import EDIMixin
|
||||
from openerp.tools.translate import _
|
||||
|
||||
from urllib import urlencode
|
||||
from werkzeug import url_encode
|
||||
|
||||
SALE_ORDER_LINE_EDI_STRUCT = {
|
||||
'sequence': True,
|
||||
|
@ -197,7 +197,7 @@ class sale_order(osv.osv, EDIMixin):
|
|||
"no_note": "1",
|
||||
"bn": "OpenERP_Order_PayNow_" + order.pricelist_id.currency_id.name,
|
||||
}
|
||||
res[order.id] = "https://www.paypal.com/cgi-bin/webscr?" + urlencode(params)
|
||||
res[order.id] = "https://www.paypal.com/cgi-bin/webscr?" + url_encode(params)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
<search string="Sales Analysis">
|
||||
<field name="date"/>
|
||||
<field name="date_confirm"/>
|
||||
<filter icon="terp-document-new" name="Quotations" domain="[('state','=','draft')]"/>
|
||||
<filter icon="terp-check" name="Sales" string="Sales" domain="[('state','not in',('draft','done','cancel'))]"/>
|
||||
<filter icon="terp-document-new" name="Quotations" domain="[('state','in',('draft','sent'))]"/>
|
||||
<filter icon="terp-check" name="Sales" string="Sales" domain="[('state','not in',('draft','sent','cancel'))]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal" string="My Sales" help="My Sales" domain="[('user_id','=',uid)]"/>
|
||||
<field name="partner_id"/>
|
||||
|
|
|
@ -358,12 +358,12 @@ class sale_order_line(osv.osv):
|
|||
uom = False
|
||||
if not uom2:
|
||||
uom2 = product_obj.uom_id
|
||||
compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
|
||||
compare_qty = float_compare(product_obj.virtual_available, qty, precision_rounding=uom2.rounding)
|
||||
if (product_obj.type=='product') and int(compare_qty) == -1:
|
||||
warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
|
||||
(qty, uom2 and uom2.name or product_obj.uom_id.name,
|
||||
max(0,product_obj.virtual_available), product_obj.uom_id.name,
|
||||
max(0,product_obj.qty_available), product_obj.uom_id.name)
|
||||
(qty, uom2.name,
|
||||
max(0,product_obj.virtual_available), uom2.name,
|
||||
max(0,product_obj.qty_available), uom2.name)
|
||||
warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
|
||||
|
||||
#update of warning messages
|
||||
|
|
|
@ -234,7 +234,7 @@ class WebsiteSurvey(http.Controller):
|
|||
|
||||
# AJAX submission of a page
|
||||
@http.route(['/survey/submit/<model("survey.survey"):survey>'],
|
||||
type='http', auth='public', website=True)
|
||||
type='http', methods=['POST'], auth='public', website=True)
|
||||
def submit(self, survey, **post):
|
||||
_logger.debug('Incoming data: %s', post)
|
||||
page_id = int(post['page_id'])
|
||||
|
@ -310,7 +310,8 @@ class WebsiteSurvey(http.Controller):
|
|||
current_filters = survey_obj.filter_input_ids(request.cr, request.uid, filter_data, filter_finish, context=request.context)
|
||||
filter_display_data = survey_obj.get_filter_display_data(request.cr, request.uid, filter_data, context=request.context)
|
||||
return request.website.render(result_template,
|
||||
{'survey_dict': self.prepare_result_dict(survey, current_filters),
|
||||
{'survey': survey,
|
||||
'survey_dict': self.prepare_result_dict(survey, current_filters),
|
||||
'page_range': self.page_range,
|
||||
'current_filters': current_filters,
|
||||
'filter_display_data': filter_display_data,
|
||||
|
|
|
@ -46,6 +46,8 @@ instance.web.Notification = instance.web.Widget.extend({
|
|||
}
|
||||
});
|
||||
|
||||
var opened_modal = [];
|
||||
|
||||
instance.web.action_notify = function(element, action) {
|
||||
element.do_notify(action.params.title, action.params.text, action.params.sticky);
|
||||
};
|
||||
|
@ -113,6 +115,8 @@ instance.web.Dialog = instance.web.Widget.extend({
|
|||
this.init_dialog();
|
||||
}
|
||||
this.$buttons.insertAfter(this.$dialog_box.find(".modal-body"));
|
||||
//add to list of currently opened modal
|
||||
opened_modal.push(this.$dialog_box);
|
||||
return this;
|
||||
},
|
||||
_add_buttons: function(buttons) {
|
||||
|
@ -152,7 +156,7 @@ instance.web.Dialog = instance.web.Widget.extend({
|
|||
'keyboard': true,
|
||||
});
|
||||
if (options.size !== 'large'){
|
||||
var dialog_class_size = this.$dialog_box.find('.modal-lg').removeClass('modal-lg')
|
||||
var dialog_class_size = this.$dialog_box.find('.modal-lg').removeClass('modal-lg');
|
||||
if (options.size === 'small'){
|
||||
dialog_class_size.addClass('modal-sm');
|
||||
}
|
||||
|
@ -165,7 +169,7 @@ instance.web.Dialog = instance.web.Widget.extend({
|
|||
}
|
||||
$dialog_content.openerpClass();
|
||||
|
||||
this.$dialog_box.on('hidden.bs.modal', this, function(){
|
||||
this.$dialog_box.on('hidden.bs.modal', this, function() {
|
||||
self.close();
|
||||
});
|
||||
this.$dialog_box.modal('show');
|
||||
|
@ -175,13 +179,15 @@ instance.web.Dialog = instance.web.Widget.extend({
|
|||
return res;
|
||||
},
|
||||
/**
|
||||
Closes the popup, if destroy_on_close was passed to the constructor, it is also destroyed.
|
||||
Closes (hide) the popup, if destroy_on_close was passed to the constructor, it will be destroyed instead.
|
||||
*/
|
||||
close: function(reason) {
|
||||
if (this.dialog_inited) {
|
||||
if (this.dialog_inited && !this.__tmp_dialog_hiding) {
|
||||
this.trigger("closing", reason);
|
||||
if (this.$el.is(":data(bs.modal)")) { // may have been destroyed by closing signal
|
||||
this.$el.parents('.modal').modal('hide');
|
||||
this.__tmp_dialog_hiding = true;
|
||||
this.$dialog_box.modal('hide');
|
||||
this.__tmp_dialog_hiding = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -212,9 +218,17 @@ instance.web.Dialog = instance.web.Widget.extend({
|
|||
//we need this to put the instruction to remove modal from DOM at the end
|
||||
//of the queue, otherwise it might already have been removed before the modal-backdrop
|
||||
//is removed when pressing escape key
|
||||
var $parent = this.$el.parents('.modal');
|
||||
var $element = this.$dialog_box;
|
||||
setTimeout(function () {
|
||||
$parent.remove();
|
||||
//remove modal from list of opened modal since we just destroy it
|
||||
var modal_list_index = $.inArray($element, opened_modal);
|
||||
if (modal_list_index > -1){
|
||||
opened_modal.splice(modal_list_index,1)[0].remove();
|
||||
}
|
||||
if (opened_modal.length > 0){
|
||||
//we still have other opened modal so we should focus it
|
||||
opened_modal[opened_modal.length-1].focus();
|
||||
}
|
||||
},0);
|
||||
}
|
||||
this._super();
|
||||
|
@ -239,8 +253,7 @@ instance.web.CrashManager = instance.web.Class.extend({
|
|||
this.show_warning({type: "Session Expired", data: { message: _t("Your OpenERP session expired. Please refresh the current web page.") }});
|
||||
return;
|
||||
}
|
||||
if (error.data.exception_type === "except_osv" || error.data.exception_type === "warning"
|
||||
|| error.data.exception_type === "access_error") {
|
||||
if (error.data.exception_type === "except_osv" || error.data.exception_type === "warning" || error.data.exception_type === "access_error") {
|
||||
this.show_warning(error);
|
||||
} else {
|
||||
this.show_error(error);
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import cStringIO
|
||||
import contextlib
|
||||
import hashlib
|
||||
import datetime
|
||||
from itertools import islice
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import datetime
|
||||
import re
|
||||
|
||||
from sys import maxint
|
||||
|
||||
import werkzeug
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.utils
|
||||
import werkzeug.wrappers
|
||||
from PIL import Image
|
||||
|
||||
import openerp
|
||||
from openerp.osv import fields
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.addons.web import http
|
||||
from openerp.http import request, Response
|
||||
|
||||
|
@ -27,6 +21,7 @@ logger = logging.getLogger(__name__)
|
|||
# Completely arbitrary limits
|
||||
MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT = IMAGE_LIMITS = (1024, 768)
|
||||
LOC_PER_SITEMAP = 45000
|
||||
SITEMAP_CACHE_TIME = datetime.timedelta(hours=12)
|
||||
|
||||
class Website(openerp.addons.web.controllers.main.Home):
|
||||
#------------------------------------------------------
|
||||
|
@ -52,7 +47,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
# TODO: can't we just put auth=public, ... in web client ?
|
||||
return super(Website, self).web_login(*args, **kw)
|
||||
|
||||
@http.route('/page/<page:page>', type='http', auth="public", website=True)
|
||||
@http.route('/page/<path:page>', type='http', auth="public", website=True)
|
||||
def page(self, page, **opt):
|
||||
values = {
|
||||
'path': page,
|
||||
|
@ -78,33 +73,64 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
|
||||
@http.route('/sitemap.xml', type='http', auth="public", website=True)
|
||||
def sitemap_xml_index(self):
|
||||
pages = list(request.website.enumerate_pages())
|
||||
if len(pages)<=LOC_PER_SITEMAP:
|
||||
return self.__sitemap_xml(pages, 0)
|
||||
# Sitemaps must be split in several smaller files with a sitemap index
|
||||
values = {
|
||||
'pages': range(len(pages)/LOC_PER_SITEMAP+1),
|
||||
'url_root': request.httprequest.url_root
|
||||
}
|
||||
headers = {
|
||||
'Content-Type': 'application/xml;charset=utf-8',
|
||||
}
|
||||
return request.render('website.sitemap_index_xml', values, headers=headers)
|
||||
cr, uid, context = request.cr, openerp.SUPERUSER_ID, request.context
|
||||
ira = request.registry['ir.attachment']
|
||||
iuv = request.registry['ir.ui.view']
|
||||
mimetype ='application/xml;charset=utf-8'
|
||||
content = None
|
||||
|
||||
@http.route('/sitemap-<int:page>.xml', type='http', auth="public", website=True)
|
||||
def sitemap_xml(self, page):
|
||||
pages = list(request.website.enumerate_pages())
|
||||
return self.__sitemap_xml(pages, page)
|
||||
def create_sitemap(url, content):
|
||||
ira.create(cr, uid, dict(
|
||||
datas=content.encode('base64'),
|
||||
mimetype=mimetype,
|
||||
type='binary',
|
||||
name=url,
|
||||
url=url,
|
||||
), context=context)
|
||||
|
||||
def __sitemap_xml(self, pages, index=0):
|
||||
values = {
|
||||
'pages': pages[index*LOC_PER_SITEMAP:(index+1)*LOC_PER_SITEMAP],
|
||||
'url_root': request.httprequest.url_root.rstrip('/')
|
||||
}
|
||||
headers = {
|
||||
'Content-Type': 'application/xml;charset=utf-8',
|
||||
}
|
||||
return request.render('website.sitemap_xml', values, headers=headers)
|
||||
sitemap = ira.search_read(cr, uid, [('url', '=' , '/sitemap.xml'), ('type', '=', 'binary')], ('datas', 'create_date'), context=context)
|
||||
if sitemap:
|
||||
# Check if stored version is still valid
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
create_date = datetime.datetime.strptime(sitemap[0]['create_date'], server_format)
|
||||
delta = datetime.datetime.now() - create_date
|
||||
if delta < SITEMAP_CACHE_TIME:
|
||||
content = sitemap[0]['datas'].decode('base64')
|
||||
|
||||
if not content:
|
||||
# Remove all sitemaps in ir.attachments as we're going to regenerated them
|
||||
sitemap_ids = ira.search(cr, uid, [('url', '=like' , '/sitemap%.xml'), ('type', '=', 'binary')], context=context)
|
||||
if sitemap_ids:
|
||||
ira.unlink(cr, uid, sitemap_ids, context=context)
|
||||
|
||||
pages = 0
|
||||
first_page = None
|
||||
locs = request.website.enumerate_pages()
|
||||
while True:
|
||||
start = pages * LOC_PER_SITEMAP
|
||||
loc_slice = islice(locs, start, start + LOC_PER_SITEMAP)
|
||||
urls = iuv.render(cr, uid, 'website.sitemap_locs', dict(locs=loc_slice), context=context)
|
||||
if urls.strip():
|
||||
page = iuv.render(cr, uid, 'website.sitemap_xml', dict(content=urls), context=context)
|
||||
if not first_page:
|
||||
first_page = page
|
||||
pages += 1
|
||||
create_sitemap('/sitemap-%d.xml' % pages, page)
|
||||
else:
|
||||
break
|
||||
if not pages:
|
||||
return request.not_found()
|
||||
elif pages == 1:
|
||||
content = first_page
|
||||
else:
|
||||
# Sitemaps must be split in several smaller files with a sitemap index
|
||||
content = iuv.render(cr, uid, 'website.sitemap_index_xml', dict(
|
||||
pages=range(1, pages + 1),
|
||||
url_root=request.httprequest.url_root,
|
||||
), context=context)
|
||||
create_sitemap('/sitemap.xml', content)
|
||||
|
||||
return request.make_response(content, [('Content-Type', mimetype)])
|
||||
|
||||
#------------------------------------------------------
|
||||
# Edit
|
||||
|
@ -332,13 +358,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
return request.website.kanban_col(**post)
|
||||
|
||||
def placeholder(self, response):
|
||||
# file_open may return a StringIO. StringIO can be closed but are
|
||||
# not context managers in Python 2 though that is fixed in 3
|
||||
with contextlib.closing(openerp.tools.misc.file_open(
|
||||
os.path.join('web', 'static', 'src', 'img', 'placeholder.png'),
|
||||
mode='rb')) as f:
|
||||
response.data = f.read()
|
||||
return response.make_conditional(request.httprequest)
|
||||
return request.registry['website']._image_placeholder(response)
|
||||
|
||||
@http.route([
|
||||
'/website/image',
|
||||
|
@ -354,60 +374,15 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
Sets and checks conditional response parameters:
|
||||
* :mailheader:`ETag` is always set (and checked)
|
||||
* :mailheader:`Last-Modified is set iif the record has a concurrency
|
||||
field (``write_date``)
|
||||
field (``__last_update``)
|
||||
|
||||
The requested field is assumed to be base64-encoded image data in
|
||||
all cases.
|
||||
"""
|
||||
id = int(id)
|
||||
response = werkzeug.wrappers.Response()
|
||||
concurrency = 'write_date'
|
||||
try:
|
||||
[record] = request.registry[model].read(request.cr, openerp.SUPERUSER_ID, [id],
|
||||
[concurrency, field],
|
||||
context=request.context)
|
||||
except:
|
||||
return self.placeholder(response)
|
||||
return request.registry['website']._image(
|
||||
request.cr, request.uid, model, id, field, response)
|
||||
|
||||
if concurrency in record:
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
try:
|
||||
response.last_modified = datetime.datetime.strptime(
|
||||
record[concurrency], server_format + '.%f')
|
||||
except ValueError:
|
||||
# just in case we have a timestamp without microseconds
|
||||
response.last_modified = datetime.datetime.strptime(
|
||||
record[concurrency], server_format)
|
||||
|
||||
# Field does not exist on model or field set to False
|
||||
if not record.get(field):
|
||||
# FIXME: maybe a field which does not exist should be a 404?
|
||||
return self.placeholder(response)
|
||||
|
||||
response.set_etag(hashlib.sha1(record[field]).hexdigest())
|
||||
response.make_conditional(request.httprequest)
|
||||
|
||||
# conditional request match
|
||||
if response.status_code == 304:
|
||||
return response
|
||||
|
||||
data = record[field].decode('base64')
|
||||
if (not max_width) and (not max_height):
|
||||
response.data = data
|
||||
return response
|
||||
|
||||
image = Image.open(cStringIO.StringIO(data))
|
||||
response.mimetype = Image.MIME[image.format]
|
||||
|
||||
w, h = image.size
|
||||
max_w, max_h = int(max_width), int(max_height)
|
||||
if w < max_w and h < max_h:
|
||||
response.data = data
|
||||
else:
|
||||
image.thumbnail((max_w, max_h), Image.ANTIALIAS)
|
||||
image.save(response.stream, image.format)
|
||||
del response.headers['Content-Length']
|
||||
return response
|
||||
|
||||
#------------------------------------------------------
|
||||
# Server actions
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import cStringIO
|
||||
import contextlib
|
||||
import datetime
|
||||
import hashlib
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import math
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import urlparse
|
||||
|
||||
from PIL import Image
|
||||
from sys import maxint
|
||||
|
||||
import werkzeug
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.utils
|
||||
|
@ -459,6 +466,95 @@ class website(osv.osv):
|
|||
html += request.website._render(template, {'object_id': object_id})
|
||||
return html
|
||||
|
||||
def _image_placeholder(self, response):
|
||||
# file_open may return a StringIO. StringIO can be closed but are
|
||||
# not context managers in Python 2 though that is fixed in 3
|
||||
with contextlib.closing(openerp.tools.misc.file_open(
|
||||
os.path.join('web', 'static', 'src', 'img', 'placeholder.png'),
|
||||
mode='rb')) as f:
|
||||
response.data = f.read()
|
||||
return response.make_conditional(request.httprequest)
|
||||
|
||||
def _image(self, cr, uid, model, id, field, response, max_width=maxint, max_height=maxint, context=None):
|
||||
""" Fetches the requested field and ensures it does not go above
|
||||
(max_width, max_height), resizing it if necessary.
|
||||
|
||||
Resizing is bypassed if the object provides a $field_big, which will
|
||||
be interpreted as a pre-resized version of the base field.
|
||||
|
||||
If the record is not found or does not have the requested field,
|
||||
returns a placeholder image via :meth:`~._image_placeholder`.
|
||||
|
||||
Sets and checks conditional response parameters:
|
||||
* :mailheader:`ETag` is always set (and checked)
|
||||
* :mailheader:`Last-Modified is set iif the record has a concurrency
|
||||
field (``__last_update``)
|
||||
|
||||
The requested field is assumed to be base64-encoded image data in
|
||||
all cases.
|
||||
"""
|
||||
Model = self.pool[model]
|
||||
id = int(id)
|
||||
|
||||
ids = Model.search(cr, uid,
|
||||
[('id', '=', id)], context=context)
|
||||
if not ids and 'website_published' in Model._all_columns:
|
||||
ids = Model.search(cr, openerp.SUPERUSER_ID,
|
||||
[('id', '=', id), ('website_published', '=', True)], context=context)
|
||||
if not ids:
|
||||
return self._image_placeholder(response)
|
||||
|
||||
concurrency = '__last_update'
|
||||
[record] = Model.read(cr, openerp.SUPERUSER_ID, [id],
|
||||
[concurrency, field],
|
||||
context=context)
|
||||
|
||||
if concurrency in record:
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
try:
|
||||
response.last_modified = datetime.datetime.strptime(
|
||||
record[concurrency], server_format + '.%f')
|
||||
except ValueError:
|
||||
# just in case we have a timestamp without microseconds
|
||||
response.last_modified = datetime.datetime.strptime(
|
||||
record[concurrency], server_format)
|
||||
|
||||
# Field does not exist on model or field set to False
|
||||
if not record.get(field):
|
||||
# FIXME: maybe a field which does not exist should be a 404?
|
||||
return self._image_placeholder(response)
|
||||
|
||||
response.set_etag(hashlib.sha1(record[field]).hexdigest())
|
||||
response.make_conditional(request.httprequest)
|
||||
|
||||
# conditional request match
|
||||
if response.status_code == 304:
|
||||
return response
|
||||
|
||||
data = record[field].decode('base64')
|
||||
|
||||
if (not max_width) and (not max_height):
|
||||
response.data = data
|
||||
return response
|
||||
|
||||
image = Image.open(cStringIO.StringIO(data))
|
||||
response.mimetype = Image.MIME[image.format]
|
||||
|
||||
w, h = image.size
|
||||
max_w, max_h = int(max_width), int(max_height)
|
||||
|
||||
if w < max_w and h < max_h:
|
||||
response.data = data
|
||||
else:
|
||||
image.thumbnail((max_w, max_h), Image.ANTIALIAS)
|
||||
image.save(response.stream, image.format)
|
||||
# invalidate content-length computed by make_conditional as
|
||||
# writing to response.stream does not do it (as of werkzeug 0.9.3)
|
||||
del response.headers['Content-Length']
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class website_menu(osv.osv):
|
||||
_name = "website.menu"
|
||||
_description = "Website Menu"
|
||||
|
|
|
@ -121,7 +121,7 @@ header a.navbar-brand img {
|
|||
|
||||
/* ----- EDITOR ----- */
|
||||
.css_non_editable_mode_hidden {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* ----- BOOTSTRAP FIX ----- */
|
||||
|
|
|
@ -41,6 +41,9 @@ class CrawlSuite(unittest2.TestSuite):
|
|||
starting the crawl
|
||||
"""
|
||||
|
||||
at_install = False
|
||||
post_install = True
|
||||
|
||||
def __init__(self, user=None, password=None):
|
||||
super(CrawlSuite, self).__init__()
|
||||
|
||||
|
@ -108,14 +111,23 @@ class CrawlSuite(unittest2.TestSuite):
|
|||
for link in doc.xpath('//a[@href]'):
|
||||
href = link.get('href')
|
||||
|
||||
parts = urlparse.urlsplit(href)
|
||||
# href with any fragment removed
|
||||
href = urlparse.urlunsplit((
|
||||
parts.scheme,
|
||||
parts.netloc,
|
||||
parts.path,
|
||||
parts.query,
|
||||
''
|
||||
))
|
||||
|
||||
# avoid repeats, even for links we won't crawl no need to
|
||||
# bother splitting them if we've already ignored them
|
||||
# previously
|
||||
if href in seen: continue
|
||||
seen.add(href)
|
||||
|
||||
parts = urlparse.urlsplit(href)
|
||||
|
||||
# FIXME: handle relative link (not parts.path.startswith /)
|
||||
if parts.netloc or \
|
||||
not parts.path.startswith('/') or \
|
||||
parts.path == '/web' or\
|
||||
|
|
|
@ -709,14 +709,18 @@ User-agent: *
|
|||
Sitemap: <t t-esc="url_root"/>sitemap.xml
|
||||
</template>
|
||||
|
||||
<template id="sitemap_locs">
|
||||
<url t-foreach="locs" t-as="page">
|
||||
<loc><t t-esc="url_root"/><t t-esc="page['loc']"/></loc><t t-if="page.get('lastmod', False)">
|
||||
<lastmod t-esc="page['lastmod']"/></t><t t-if="page.get('priority', False)">
|
||||
<priority t-esc="page['priority']"/></t><t t-if="page.get('changefreq', False)">
|
||||
<changefreq t-esc="page['changefreq']"/></t>
|
||||
</url>
|
||||
</template>
|
||||
|
||||
<template id="sitemap_xml"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url t-foreach="pages" t-as="page">
|
||||
<loc><t t-esc="url_root"/><t t-esc="page['loc']"/></loc><t t-if="page.get('lastmod', False)">
|
||||
<lastmod t-esc="page['lastmod']"/></t><t t-if="page.get('priority', False)">
|
||||
<priority t-esc="page['priority']"/></t><t t-if="page.get('changefreq', False)">
|
||||
<changefreq t-esc="page['changefreq']"/></t>
|
||||
</url>
|
||||
<t t-raw="content"/>
|
||||
</urlset>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class WebsiteBlog(http.Controller):
|
|||
blog_post_obj = request.registry['blog.post']
|
||||
groups = blog_post_obj.read_group(
|
||||
request.cr, request.uid, [], ['name', 'create_date'],
|
||||
groupby="create_date", orderby="create_date asc", context=request.context)
|
||||
groupby="create_date", orderby="create_date desc", context=request.context)
|
||||
for group in groups:
|
||||
begin_date = datetime.datetime.strptime(group['__domain'][0][2], tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
||||
end_date = datetime.datetime.strptime(group['__domain'][1][2], tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
||||
|
@ -122,7 +122,7 @@ class WebsiteBlog(http.Controller):
|
|||
blog_url = QueryURL('', ['blog', 'tag'], blog=blog, tag=tag, date_begin=date_begin, date_end=date_end)
|
||||
post_url = QueryURL('', ['blogpost'], tag_id=tag and tag.id or None, date_begin=date_begin, date_end=date_end)
|
||||
|
||||
blog_post_ids = blog_post_obj.search(cr, uid, domain, order="create_date asc", context=context)
|
||||
blog_post_ids = blog_post_obj.search(cr, uid, domain, order="create_date desc", context=context)
|
||||
blog_posts = blog_post_obj.browse(cr, uid, blog_post_ids, context=context)
|
||||
|
||||
pager = request.website.pager(
|
||||
|
|
|
@ -29,11 +29,12 @@
|
|||
},
|
||||
}),
|
||||
edit: function () {
|
||||
var self = this;
|
||||
$('.popover').remove();
|
||||
this._super();
|
||||
var vHeight = $(window).height();
|
||||
$('body').on('click','#change_cover',_.bind(this.change_bg,{},vHeight));
|
||||
$('body').on('click', '#clear_cover',_.bind(this.clean_bg,{},vHeight));
|
||||
$('body').on('click','#change_cover',_.bind(this.change_bg, self.rte.editor, vHeight));
|
||||
$('body').on('click', '#clear_cover',_.bind(this.clean_bg, self.rte.editor, vHeight));
|
||||
},
|
||||
save : function() {
|
||||
var res = this._super();
|
||||
|
@ -50,12 +51,12 @@
|
|||
},
|
||||
change_bg : function(vHeight) {
|
||||
var self = this;
|
||||
var editor = new website.editor.ImageDialog();
|
||||
editor.on('start', self, function (o) {
|
||||
o.url = $('.js_fullheight').length ? $('.js_fullheight').css('background-image').replace(/url\(|\)|"|'/g,'') : '';
|
||||
});
|
||||
editor.on('save', self, function (o) {
|
||||
$('.js_fullheight').css({"background-image": o.url && o.url !== "" ? 'url(' + o.url + ')' : "", 'min-height': vHeight})
|
||||
var element = new CKEDITOR.dom.element(self.element.find('.cover-storage').$[0]);
|
||||
var editor = new website.editor.MediaDialog(self, element);
|
||||
$(document.body).on('media-saved', self, function (o) {
|
||||
var url = $('.cover-storage').attr('src');
|
||||
$('.js_fullheight').css({"background-image": !_.isUndefined(url) ? 'url(' + url + ')' : "", 'min-height': vHeight});
|
||||
$('.cover-storage').remove();
|
||||
});
|
||||
editor.appendTo('body');
|
||||
},
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<t t-foreach="posts" t-as="post">
|
||||
<div class="col-md-4">
|
||||
<h4>
|
||||
<a t-attf-href="#{blog_url('', ['blogpost'], blogpost=post)}" t-field="post.name"></a>
|
||||
<a t-attf-href="#{blog_url('', ['blog', 'post'], blog=post.blog_id, post=post)}" t-field="post.name"></a>
|
||||
<span t-if="not post.website_published" class="text-warning">
|
||||
&nbsp;
|
||||
<span class="fa fa-warning" title="Not published"/>
|
||||
|
@ -187,6 +187,7 @@
|
|||
<span class="fa fa-times"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="cover-storage oe_hidden"></div>
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
|
|
|
@ -16,45 +16,36 @@ class contactus(http.Controller):
|
|||
)
|
||||
return url
|
||||
|
||||
@http.route(['/page/website.contactus'], type='http', auth="public", website=True)
|
||||
@http.route(['/page/website.contactus', '/page/contactus'], type='http', auth="public", website=True)
|
||||
def contact(self, **kwargs):
|
||||
values = {}
|
||||
for field in ['description', 'partner_name', 'phone', 'contact_name', 'email_from', 'name']:
|
||||
if kwargs.get(field):
|
||||
values[field] = kwargs.pop(field)
|
||||
values.update(kwargs=kwargs.items())
|
||||
print values
|
||||
return request.website.render("website.contactus", values)
|
||||
|
||||
@http.route(['/crm/contactus'], type='http', auth="public", website=True)
|
||||
def contactus(self, description=None, partner_name=None, phone=None, contact_name=None, email_from=None, name=None, **kwargs):
|
||||
post = {}
|
||||
post['description'] = description
|
||||
post['partner_name'] = partner_name
|
||||
post['phone'] = phone
|
||||
post['contact_name'] = contact_name
|
||||
post['email_from'] = email_from
|
||||
post['name'] = name
|
||||
|
||||
required_fields = ['contact_name', 'email_from', 'description']
|
||||
error = set()
|
||||
values = dict((key, post.get(key)) for key in post)
|
||||
values['error'] = error
|
||||
post = {
|
||||
'description': description,
|
||||
'partner_name': partner_name,
|
||||
'phone': phone,
|
||||
'contact_name': contact_name,
|
||||
'email_from': email_from,
|
||||
'name': name or contact_name,
|
||||
'user_id': False,
|
||||
}
|
||||
|
||||
# fields validation
|
||||
for field in required_fields:
|
||||
if not post.get(field):
|
||||
error.add(field)
|
||||
error = set(field for field in ['contact_name', 'email_from', 'description']
|
||||
if not post.get(field))
|
||||
|
||||
values = dict(post, error=error)
|
||||
if error:
|
||||
values.update(kwargs=kwargs.items())
|
||||
return request.website.render("website.contactus", values)
|
||||
|
||||
# if not given: subject is contact name
|
||||
if not post.get('name'):
|
||||
post['name'] = post.get('contact_name')
|
||||
|
||||
post['user_id'] = False
|
||||
|
||||
try:
|
||||
post['channel_id'] = request.registry['ir.model.data'].get_object_reference(request.cr, SUPERUSER_ID, 'crm', 'crm_case_channel_website')[1]
|
||||
except ValueError:
|
||||
|
|
|
@ -10,6 +10,7 @@ Publish and Assign Partner
|
|||
'author': 'OpenERP SA',
|
||||
'depends': ['crm_partner_assign','website_partner', 'website_google_map'],
|
||||
'data': [
|
||||
'views/partner_grade.xml',
|
||||
'views/website_crm_partner_assign.xml',
|
||||
],
|
||||
'qweb': ['static/src/xml/*.xml'],
|
||||
|
|
|
@ -1,121 +1,172 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
import re
|
||||
import werkzeug
|
||||
|
||||
import openerp
|
||||
_logger = logging.getLogger(__name__)
|
||||
try:
|
||||
import GeoIP
|
||||
except ImportError:
|
||||
GeoIP = None
|
||||
_logger.warn("Please install GeoIP python module to use events localisation.")
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.web import http
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
from openerp.addons.website.models.website import slug
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class WebsiteCrmPartnerAssign(http.Controller):
|
||||
_references_per_page = 20
|
||||
_references_per_page = 40
|
||||
|
||||
def _get_current_country_code(self):
|
||||
if not GeoIP:
|
||||
return False
|
||||
GI = GeoIP.open('/usr/share/GeoIP/GeoIP.dat', 0)
|
||||
return GI.country_code_by_addr(request.httprequest.remote_addr)
|
||||
|
||||
@http.route([
|
||||
'/partners',
|
||||
'/partners/page/<int:page>',
|
||||
|
||||
'/partners/grade/<int:grade_id>',
|
||||
'/partners/grade/<int:grade_id>/page/<int:page>',
|
||||
'/partners/grade/<model("res.partner.grade"):grade>',
|
||||
'/partners/grade/<model("res.partner.grade"):grade>/page/<int:page>',
|
||||
|
||||
'/partners/country/<int:country_id>',
|
||||
'/partners/country/<country_name>-<int:country_id>',
|
||||
'/partners/country/<int:country_id>/page/<int:page>',
|
||||
'/partners/country/<country_name>-<int:country_id>/page/<int:page>',
|
||||
|
||||
'/partners/grade/<int:grade_id>/country/<int:country_id>',
|
||||
'/partners/grade/<int:grade_id>/country/<country_name>-<int:country_id>',
|
||||
'/partners/grade/<int:grade_id>/country/<int:country_id>/page/<int:page>',
|
||||
'/partners/grade/<int:grade_id>/country/<country_name>-<int:country_id>/page/<int:page>',
|
||||
|
||||
'/partners/country/<model("res.country"):country>',
|
||||
'/partners/country/<model("res.country"):country>/page/<int:page>',
|
||||
|
||||
'/partners/grade/<model("res.partner.grade"):grade>/country/<model("res.country"):country>',
|
||||
'/partners/grade/<model("res.partner.grade"):grade>/country/<model("res.country"):country>/page/<int:page>',
|
||||
], type='http', auth="public", website=True)
|
||||
def partners(self, country_id=0, grade_id=0, page=0, **post):
|
||||
country_obj = request.registry['res.country']
|
||||
def partners(self, country=None, grade=None, page=0, **post):
|
||||
country_all = post.pop('country_all', False)
|
||||
partner_obj = request.registry['res.partner']
|
||||
post_name = post.get('search', '')
|
||||
country = None
|
||||
country_obj = request.registry['res.country']
|
||||
search = post.get('search', '')
|
||||
|
||||
# format displayed membership lines domain
|
||||
base_partner_domain = [('is_company', '=', True), ('grade_id', '!=', False), ('website_published', '=', True)]
|
||||
partner_domain = list(base_partner_domain)
|
||||
if post_name:
|
||||
partner_domain += ['|', ('name', 'ilike', post_name), ('website_description', 'ilike', post_name)]
|
||||
if grade_id and grade_id != "all":
|
||||
partner_domain += [('grade_id', '=', int(grade_id))] # try/catch int
|
||||
|
||||
# group by country
|
||||
countries = partner_obj.read_group(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
countries_partners = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context, count=True)
|
||||
|
||||
if country_id:
|
||||
country = country_obj.browse(request.cr, request.uid, country_id, request.context)
|
||||
partner_domain += [('country_id', '=', country_id)]
|
||||
if not any(x['country_id'][0] == country_id for x in countries):
|
||||
countries.append({
|
||||
'country_id_count': 0,
|
||||
'country_id': (country_id, country.name)
|
||||
})
|
||||
countries.sort(key=lambda d: d['country_id'][1])
|
||||
|
||||
countries.insert(0, {
|
||||
'country_id_count': countries_partners,
|
||||
'country_id': (0, _("All Countries"))
|
||||
})
|
||||
|
||||
|
||||
# format pager
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context)
|
||||
pager = request.website.pager(url="/partners", total=len(partner_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
|
||||
|
||||
# search for partners to display
|
||||
partners_data = partner_obj.search_read(request.cr, openerp.SUPERUSER_ID,
|
||||
domain=partner_domain,
|
||||
fields=request.website.get_partner_white_list_fields(),
|
||||
offset=pager['offset'],
|
||||
limit=self._references_per_page,
|
||||
order="grade_id DESC,partner_weight DESC",
|
||||
context=request.context)
|
||||
google_map_partner_ids = ",".join([str(p['id']) for p in partners_data])
|
||||
base_partner_domain = [('is_company', '=', True), ('grade_id.website_published', '=', True), ('website_published', '=', True)]
|
||||
if search:
|
||||
base_partner_domain += ['|', ('name', 'ilike', search), ('website_description', 'ilike', search)]
|
||||
|
||||
# group by grade
|
||||
grade_domain = list(base_partner_domain)
|
||||
if not country and not country_all:
|
||||
country_code = self._get_current_country_code()
|
||||
if country_code:
|
||||
country_ids = country_obj.search(request.cr, request.uid, [('code', '=', country_code)], context=request.context)
|
||||
if country_ids:
|
||||
country = country_obj.browse(request.cr, request.uid, country_ids[0], context=request.context)
|
||||
if country:
|
||||
grade_domain += [('country_id', '=', country.id)]
|
||||
grades = partner_obj.read_group(
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain, ["id", "grade_id"],
|
||||
groupby="grade_id", orderby="grade_id", context=request.context)
|
||||
request.cr, SUPERUSER_ID, grade_domain, ["id", "grade_id"],
|
||||
groupby="grade_id", orderby="grade_id DESC", context=request.context)
|
||||
grades_partners = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, base_partner_domain,
|
||||
request.cr, SUPERUSER_ID, grade_domain,
|
||||
context=request.context, count=True)
|
||||
# flag active grade
|
||||
for grade_dict in grades:
|
||||
grade_dict['active'] = grade and grade_dict['grade_id'][0] == grade.id
|
||||
grades.insert(0, {
|
||||
'grade_id_count': grades_partners,
|
||||
'grade_id': (0, _("All Categories"))
|
||||
'grade_id': (0, _("All Categories")),
|
||||
'active': bool(grade is None),
|
||||
})
|
||||
|
||||
# group by country
|
||||
country_domain = list(base_partner_domain)
|
||||
if grade:
|
||||
country_domain += [('grade_id', '=', grade.id)]
|
||||
countries = partner_obj.read_group(
|
||||
request.cr, SUPERUSER_ID, country_domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
countries_partners = partner_obj.search(
|
||||
request.cr, SUPERUSER_ID, country_domain,
|
||||
context=request.context, count=True)
|
||||
# flag active country
|
||||
for country_dict in countries:
|
||||
country_dict['active'] = country and country_dict['country_id'] and country_dict['country_id'][0] == country.id
|
||||
countries.insert(0, {
|
||||
'country_id_count': countries_partners,
|
||||
'country_id': (0, _("All Countries")),
|
||||
'active': bool(country is None),
|
||||
})
|
||||
|
||||
# current search
|
||||
if grade:
|
||||
base_partner_domain += [('grade_id', '=', grade.id)]
|
||||
if country:
|
||||
base_partner_domain += [('country_id', '=', country.id)]
|
||||
|
||||
# format pager
|
||||
if grade and not country:
|
||||
url = '/partners/grade/' + slug(grade)
|
||||
elif country and not grade:
|
||||
url = '/partners/country/' + slug(country)
|
||||
elif country and grade:
|
||||
url = '/partners/grade/' + slug(grade) + '/country/' + slug(country)
|
||||
else:
|
||||
url = '/partners'
|
||||
url_args = {}
|
||||
if search:
|
||||
url_args['search'] = search
|
||||
partner_count = partner_obj.search_count(
|
||||
request.cr, SUPERUSER_ID, base_partner_domain,
|
||||
context=request.context)
|
||||
pager = request.website.pager(
|
||||
url=url, total=partner_count, page=page, step=self._references_per_page, scope=7,
|
||||
url_args=url_args)
|
||||
|
||||
# search partners matching current search parameters
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, SUPERUSER_ID, base_partner_domain,
|
||||
order="grade_id DESC",
|
||||
context=request.context) # todo in trunk: order="grade_id DESC, implemented_count DESC", offset=pager['offset'], limit=self._references_per_page
|
||||
partners = partner_obj.browse(request.cr, SUPERUSER_ID, partner_ids, request.context)
|
||||
# remove me in trunk
|
||||
partners.sort(key=lambda x: (-1 * (x.grade_id and x.grade_id.id or 0), len(x.implemented_partner_ids)), reverse=True)
|
||||
partners = partners[pager['offset']:pager['offset'] + self._references_per_page]
|
||||
|
||||
google_map_partner_ids = ','.join(map(str, [p.id for p in partners]))
|
||||
|
||||
values = {
|
||||
'countries': countries,
|
||||
'current_country_id': country_id,
|
||||
'current_country': country,
|
||||
'grades': grades,
|
||||
'grade_id': grade_id,
|
||||
'partners_data': partners_data,
|
||||
'current_grade': grade,
|
||||
'partners': partners,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'searches': post,
|
||||
'search_path': "?%s" % werkzeug.url_encode(post),
|
||||
'search_path': "%s" % werkzeug.url_encode(post),
|
||||
}
|
||||
return request.website.render("website_crm_partner_assign.index", values)
|
||||
|
||||
# Do not use semantic controller due to SUPERUSER_ID
|
||||
@http.route(['/partners/<int:partner_id>', '/partners/<partner_name>-<int:partner_id>'], type='http', auth="public", website=True)
|
||||
def partners_ref(self, partner_id, **post):
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
values = website_partner.get_partner_template_value(partner)
|
||||
if not values:
|
||||
return self.partners(**post)
|
||||
values['main_object'] = values['partner']
|
||||
return request.website.render("website_crm_partner_assign.partner", values)
|
||||
@http.route(['/partners/<partner_id>'], type='http', auth="public", website=True)
|
||||
def partners_detail(self, partner_id, partner_name='', **post):
|
||||
mo = re.search('-([-0-9]+)$', str(partner_id))
|
||||
current_grade, current_country = None, None
|
||||
grade_id = post.get('grade_id')
|
||||
country_id = post.get('country_id')
|
||||
if grade_id:
|
||||
grade_ids = request.registry['res.partner.grade'].exists(request.cr, request.uid, int(grade_id), context=request.context)
|
||||
if grade_ids:
|
||||
current_grade = request.registry['res.partner.grade'].browse(request.cr, request.uid, grade_ids[0], context=request.context)
|
||||
if country_id:
|
||||
country_ids = request.registry['res.country'].exists(request.cr, request.uid, int(country_id), context=request.context)
|
||||
if country_ids:
|
||||
current_country = request.registry['res.country'].browse(request.cr, request.uid, country_ids[0], context=request.context)
|
||||
if mo:
|
||||
partner_id = int(mo.group(1))
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
if partner.exists() and partner.website_published:
|
||||
values = {
|
||||
'main_object': partner,
|
||||
'partner': partner,
|
||||
'current_grade': current_grade,
|
||||
'current_country': current_country
|
||||
}
|
||||
return request.website.render("website_crm_partner_assign.partner", values)
|
||||
return self.partners(**post)
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
import res_partner
|
||||
import website
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
class res_partner_grade(osv.osv):
|
||||
_inherit = 'res.partner.grade'
|
||||
_columns = {
|
||||
'website_description': fields.html('Description for the website'),
|
||||
'website_published': fields.boolean('Published On Website'),
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import orm
|
||||
|
||||
|
||||
class Website(orm.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
def get_partner_white_list_fields(self, cr, uid, ids, context=None):
|
||||
fields = super(Website, self).get_partner_white_list_fields(cr, uid, ids, context=context)
|
||||
fields += ["grade_id"]
|
||||
return fields
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="partner_grade_view">
|
||||
<field name="name">res.partner.grade.website</field>
|
||||
<field name="model">res.partner.grade</field>
|
||||
<field name="inherit_id" ref="crm_partner_assign.view_partner_grade_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="active" position="after">
|
||||
<field name="website_published"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<t t-set="additional_title">Resellers</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container">
|
||||
<div class="container mt16">
|
||||
<div class="row">
|
||||
<t t-raw="ref_content" />
|
||||
</div>
|
||||
|
@ -36,13 +36,13 @@
|
|||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb32" id="partner_left">
|
||||
<div class="col-md-3 mb32" id="partner_left">
|
||||
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<li class="nav-header"><h3>Categories</h3></li>
|
||||
<ul id="reseller_grades" class="nav nav-pills nav-stacked mt16">
|
||||
<li class="nav-header"><h3>Filter by Grade</h3></li>
|
||||
<t t-foreach="grades" t-as="grade">
|
||||
<li t-if="grade['grade_id']" t-att-class="grade['grade_id'][0] == grade_id and 'active' or ''">
|
||||
<a t-attf-href="#{ grade['grade_id'][0] and '/partners/grade/%s' % grade['grade_id'][0] or '/partners' }#{ current_country_id and ('/country/%s' % current_country_id) or '' }#{ search_path }">
|
||||
<li t-att-class="grade['active'] and 'active' or ''">
|
||||
<a t-attf-href="/partners#{ grade['grade_id'][0] and '/grade/%s' % grade['grade_id'][0] or '' }#{ current_country and '/country/%s' % slug(current_country) or '' }#{ '?' + (search_path or '') }">
|
||||
<span class="badge pull-right" t-esc="grade['grade_id_count'] or ''"/>
|
||||
<t t-esc="grade['grade_id'][1]"/>
|
||||
</a>
|
||||
|
@ -51,58 +51,63 @@
|
|||
</ul>
|
||||
|
||||
<ul id="reseller_countries" class="nav nav-pills nav-stacked mt16">
|
||||
<li class="nav-header"><h3>Locations</h3></li>
|
||||
<t t-foreach="countries" t-as="country_dict">
|
||||
<t t-if="country_dict['country_id']">
|
||||
<li t-att-class="country_dict['country_id'][0] == current_country_id and 'active' or ''">
|
||||
<a t-attf-href="#{ country_dict['country_id'][0] and ('/partners/country/%s' % slug(country_dict['country_id'])) or '/partners' }#{ search_path }">
|
||||
<span class="badge pull-right" t-esc="country_dict['country_id_count'] or ''"/>
|
||||
<t t-esc="country_dict['country_id'][1]"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
<li class="nav-header"><h3>Filter by Country</h3></li>
|
||||
<t t-foreach="countries" t-as="country">
|
||||
<li t-if="country['country_id']" t-att-class="country['active'] and 'active' or ''">
|
||||
<a t-attf-href="/partners#{ current_grade and '/grade/%s' % slug(current_grade) or ''}#{country['country_id'][0] and '/country/%s' % country['country_id'][0] or '' }#{ '?' + (search_path or '') + (country['country_id'][0] == 0 and 'country_all=True' or '')}">
|
||||
<span class="badge pull-right" t-esc="country['country_id_count'] or ''"/>
|
||||
<t t-esc="country['country_id'][1]"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-8" id="ref_content">
|
||||
<div class="col-md-8 col-md-offset-1" id="ref_content">
|
||||
<div class='navbar'>
|
||||
<div>
|
||||
<t t-call="website.pager">
|
||||
<t t-set="classname">pull-left</t>
|
||||
</t>
|
||||
<t t-call="website.pager"/>
|
||||
<form action="" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<div class="form-group">
|
||||
<div class="form-group pull-right">
|
||||
<input type="text" name="search" class="search-query col-md-2 mt4 form-control" placeholder="Search" t-att-value="searches.get('search', '')"/>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<t t-if="not partners_data">
|
||||
<p>No result found.</p>
|
||||
</t>
|
||||
<t t-foreach="partners_data" t-as="partner_data">
|
||||
<t t-if="internal_gid != partner_data['grade_id'][1]">
|
||||
<p t-if="not partners">No result found</p>
|
||||
<t t-foreach="partners" t-as="partner">
|
||||
<t t-if="last_grade != partner.grade_id.id">
|
||||
<h3 class="text-center">
|
||||
<span t-esc="partner_data['grade_id'][1]"/> Partners
|
||||
<t t-if="current_country"> in <t t-esc="current_country.name"/></t>
|
||||
<span t-field="partner.grade_id"/> Partners
|
||||
</h3>
|
||||
<t t-set="internal_gid" t-value="partner_data['grade_id'][1]"/>
|
||||
<t t-set="last_grade" t-value="partner.grade_id.id"/>
|
||||
</t>
|
||||
<div class="media">
|
||||
<a class="pull-left" t-attf-href="/partners/#{ slug([partner_data.get('id'), partner_data.get('name')]) }">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data['image_small']}"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/partners/#{ slug([partner_data.get('id'), partner_data.get('name')]) }"><t t-if="partner_data['parent_id']"><span t-esc="partner_data['parent_id'][1]"/></t> <span t-esc="partner_data['name']"/></a> - <span t-esc="partner_data['grade_id'][1]"/>
|
||||
<div t-esc="partner_data['website_short_description']"/>
|
||||
<a class="pull-left" t-attf-href="/partners/#{slug(partner)}?#{current_grade and 'grade_id=%s&' % current_grade.id}#{current_country and 'country_id=%s' % current_country.id}"
|
||||
t-field="partner.image_small"
|
||||
t-field-options='{"widget": "image", "class": "media-object"}'
|
||||
></a>
|
||||
<div class="media-body o_partner_body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/partners/#{slug(partner)}?#{current_grade and 'grade_id=%s&' % current_grade.id}#{current_country and 'country_id=%s' % current_country.id}">
|
||||
<span t-field="partner.display_name"/>
|
||||
</a>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
<t t-if="any([p.website_published for p in partner.implemented_partner_ids])">
|
||||
<small><a t-attf-href="/partners/#{slug(partner)}#right_column">
|
||||
<t t-raw="len([p for p in partner.implemented_partner_ids if p.website_published])"/> reference(s)
|
||||
</a></small>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div class='navbar'>
|
||||
<t t-call="website.pager">
|
||||
<t t-set="classname">pull-left</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
@ -112,8 +117,8 @@
|
|||
<xpath expr="//ul[@id='reseller_countries']" position="after">
|
||||
<h3>World Map</h3>
|
||||
<ul class="nav">
|
||||
<iframe t-attf-src="/google_map/?width=320&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners"
|
||||
style="width:320px; height:260px; border:0; padding:0; margin:0;"></iframe>
|
||||
<iframe t-attf-src="/google_map/?width=260&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners"
|
||||
style="width:260px; height:260px; border:0; padding:0; margin:0;"></iframe>
|
||||
</ul>
|
||||
</xpath>
|
||||
</template>
|
||||
|
@ -121,10 +126,46 @@
|
|||
<template id="partner" name="Partner Detail">
|
||||
<t t-call="website_crm_partner_assign.layout">
|
||||
<t t-set="ref_content">
|
||||
<t t-call="website_partner.partner_detail"/>
|
||||
<div class="col-md-5">
|
||||
<ol class="breadcrumb">
|
||||
<li><a t-attf-href="/partners#{current_grade and '/grade/%s' % slug(current_grade)}#{current_country and '/country/%s' % slug(current_country)}">Our Partners</a></li>
|
||||
<li class="active"><span t-field="partner.display_name"/></li>
|
||||
</ol>
|
||||
</div>
|
||||
<t t-call="website_partner.partner_detail">
|
||||
<t t-set="right_column">
|
||||
<div id="right_column" class="mb16"><t t-call="website_crm_partner_assign.references_block"/></div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="grade_in_detail" inherit_id="website_partner.partner_detail">
|
||||
<xpath expr="//*[@id='partner_name']" position="after">
|
||||
<h3 class="col-md-12 text-center text-muted" t-if="partner.grade_id and partner.grade_id.website_published">
|
||||
<span t-field="partner.grade_id"/> Partner</h3>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="references_block" name="Partner References Block">
|
||||
<t t-if="any([p.website_published for p in partner.implemented_partner_ids])">
|
||||
<h3 id="references">References</h3>
|
||||
<div t-foreach="partner.implemented_partner_ids" t-as="reference" class="media">
|
||||
<t t-if="reference.website_published">
|
||||
<a class="pull-left" t-attf-href="/customers/#{slug(reference)}">
|
||||
<span t-field="reference.image_small" t-field-options='{"widget": "image", "class": "center-block"}'/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/customers/#{slug(reference)}">
|
||||
<span t-field="reference.self"/>
|
||||
</a>
|
||||
<div t-field='reference.website_short_description'/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -30,8 +30,9 @@ OpenERP Customer References
|
|||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': [
|
||||
'crm_partner_assign',
|
||||
'website_partner',
|
||||
'website_google_map'
|
||||
'website_google_map',
|
||||
],
|
||||
'demo': [
|
||||
'website_customer_demo.xml',
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.web import http
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
import werkzeug.urls
|
||||
|
||||
class WebsiteCustomer(http.Controller):
|
||||
|
@ -19,14 +19,13 @@ class WebsiteCustomer(http.Controller):
|
|||
'/customers/country/<int:country_id>/page/<int:page>',
|
||||
'/customers/country/<country_name>-<int:country_id>/page/<int:page>',
|
||||
], type='http', auth="public", website=True)
|
||||
def customers(self, country_id=0, page=0, **post):
|
||||
def customers(self, country_id=0, page=0, country_name='', **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
country_obj = request.registry['res.country']
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_name = post.get('search', '')
|
||||
|
||||
base_domain = [('website_published','=',True)]
|
||||
domain = list(base_domain)
|
||||
domain = [('website_published', '=', True), ('assigned_partner_id', '!=', False)]
|
||||
if partner_name:
|
||||
domain += [
|
||||
'|',
|
||||
|
@ -57,25 +56,24 @@ class WebsiteCustomer(http.Controller):
|
|||
})
|
||||
|
||||
# search customers to display
|
||||
partner_ids = partner_obj.search(cr, openerp.SUPERUSER_ID, domain, context=request.context)
|
||||
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
|
||||
partner_count = partner_obj.search_count(cr, openerp.SUPERUSER_ID, domain, context=request.context)
|
||||
|
||||
# pager
|
||||
pager = request.website.pager(
|
||||
url="/customers", total=len(partner_ids), page=page, step=self._references_per_page,
|
||||
url="/customers", total=partner_count, page=page, step=self._references_per_page,
|
||||
scope=7, url_args=post
|
||||
)
|
||||
|
||||
# browse page of customers to display
|
||||
partner_ids = partner_obj.search(
|
||||
cr, openerp.SUPERUSER_ID, domain,
|
||||
limit=self._references_per_page, offset=pager['offset'], context=context)
|
||||
partners_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_ids, request.website.get_partner_white_list_fields(), context=request.context)
|
||||
partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, domain,
|
||||
offset=pager['offset'], limit=self._references_per_page,
|
||||
context=request.context)
|
||||
google_map_partner_ids = ','.join(map(str, partner_ids))
|
||||
partners = partner_obj.browse(request.cr, openerp.SUPERUSER_ID, partner_ids, request.context)
|
||||
|
||||
values = {
|
||||
'countries': countries,
|
||||
'current_country_id': country_id or 0,
|
||||
'partners_data': partners_data,
|
||||
'partners': partners,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'post': post,
|
||||
|
@ -83,26 +81,15 @@ class WebsiteCustomer(http.Controller):
|
|||
}
|
||||
return request.website.render("website_customer.index", values)
|
||||
|
||||
@http.route(['/customers/<int:partner_id>', '/customers/<partner_name>-<int:partner_id>'], type='http', auth="public", website=True)
|
||||
def customer(self, partner_id, **post):
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
values = website_partner.get_partner_template_value(partner)
|
||||
if not values:
|
||||
return self.customers(**post)
|
||||
|
||||
partner_obj = request.registry['res.partner']
|
||||
if values['partner_data'].get('assigned_partner_id', None):
|
||||
values['assigned_partner_data'] = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, [values['partner_data']['assigned_partner_id'][0]],
|
||||
request.website.get_partner_white_list_fields(), context=request.context)[0]
|
||||
if values['partner_data'].get('implemented_partner_ids', None):
|
||||
implemented_partners_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, values['partner_data']['implemented_partner_ids'],
|
||||
request.website.get_partner_white_list_fields(), context=request.context)
|
||||
values['implemented_partners_data'] = []
|
||||
for data in implemented_partners_data:
|
||||
if data.get('website_published'):
|
||||
values['implemented_partners_data'].append(data)
|
||||
|
||||
values['main_object'] = values['partner']
|
||||
return request.website.render("website_customer.details", values)
|
||||
# Do not use semantic controller due to SUPERUSER_ID
|
||||
@http.route(['/customers/<partner_id>'], type='http', auth="public", website=True)
|
||||
def partners_detail(self, partner_id, **post):
|
||||
mo = re.search('-([-0-9]+)$', str(partner_id))
|
||||
if mo:
|
||||
partner_id = int(mo.group(1))
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
if partner.exists() and partner.website_published:
|
||||
values = {}
|
||||
values['main_object'] = values['partner'] = partner
|
||||
return request.website.render("website_customer.details", values)
|
||||
return self.customers(**post)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-3 mb32" id="ref_left_column">
|
||||
</div>
|
||||
<div class="col-md-9" id="ref_content">
|
||||
<div class="col-md-8 col-md-offset-1" id="ref_content">
|
||||
<div class='navbar mb0'>
|
||||
<t t-call="website.pager">
|
||||
<t t-set="classname" t-value="'pull-left'"/>
|
||||
|
@ -39,21 +39,22 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<t t-if="not partners_data">
|
||||
<p>No result found.</p>
|
||||
</t>
|
||||
<t t-foreach="partners_data" t-as="partner_data" class="media">
|
||||
<div class="media">
|
||||
<a class="pull-left" t-attf-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data.get('image_small')}"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a t-attf-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }" t-esc="partner_data.get('name')"/>
|
||||
<div t-raw="partner_data.get('website_short_description') or ''"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix mb8"/>
|
||||
</t>
|
||||
|
||||
<p t-if="not partners">No result found</p>
|
||||
<t t-foreach="partners" t-as="partner">
|
||||
<div class="media">
|
||||
<a class="pull-left" t-attf-href="/customers/#{slug(partner)}"
|
||||
t-field="partner.image_small"
|
||||
t-field-options='{"widget": "image", "class": "media-object"}'
|
||||
></a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/customers/#{slug(partner)}">
|
||||
<span t-field="partner.display_name"/>
|
||||
</a>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -101,15 +102,15 @@
|
|||
<div class="col-md-5">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="/customers">Our References</a></li>
|
||||
<li class="active"><span t-esc="partner_data.get('name')"/></li>
|
||||
<li class="active"><span t-field="partner.display_name"/></li>
|
||||
</ol>
|
||||
</div>
|
||||
<t t-call="website_partner.partner_detail">
|
||||
<t t-set="left_column">
|
||||
<div id="left_column"></div>
|
||||
<div id="left_column"><t t-call="website_customer.implemented_by_block"/></div>
|
||||
</t>
|
||||
<t t-set="right_column">
|
||||
<div id="right_column"></div>
|
||||
<div id="right_column"><t t-call="website_customer.references_block"/></div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
|
@ -119,57 +120,59 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<template id="partner_assign" inherit_option_id="website_customer.details" inherit_id="website_customer.details" name="Implemented By">
|
||||
<xpath expr="//div[@id='left_column']" position="inside">
|
||||
<t t-if="assigned_partner_data">
|
||||
<template id="partner_details" inherit_id="website_partner.partner_page" name="Partner Detail Columns">
|
||||
<xpath expr="//t[@t-call='website_partner.partner_detail']" position="inside">
|
||||
<t t-set="left_column"><div id="left_column"><t t-call="website_customer.implemented_by_block"/></div></t>
|
||||
<t t-set="right_column"><div id="right_column"><t t-call="website_customer.references_block"/></div></t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="implemented_by_block" name="Partner Implemented By Block">
|
||||
<t t-if="partner.assigned_partner_id and partner.assigned_partner_id.website_published">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>Implemented By</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
<img class="img img-shadow" t-attf-src="data:image/png;base64,#{assigned_partner_data.get('image_medium')}"/>
|
||||
</div>
|
||||
<address class="mt16 mb8">
|
||||
<strong t-esc="assigned_partner_data.get('name')"/>
|
||||
<div t-if="assigned_partner_data.get('phone')">
|
||||
<span class="fa fa-phone"/> <span t-esc="assigned_partner_data.get('phone')"/>
|
||||
</div>
|
||||
<div t-if="assigned_partner_data.get('email')">
|
||||
<span class="fa fa-envelope"/>
|
||||
<a t-att-href="'mailto:'+assigned_partner_data.get('email')">
|
||||
<span t-esc="assigned_partner_data.get('email')"/>
|
||||
</a>
|
||||
</div>
|
||||
</address>
|
||||
<div>
|
||||
<a t-attf-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }/#references" t-if="implemented_partner_ids">
|
||||
<t t-esc="len(implemented_partner_ids)"/> references
|
||||
</a>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<h4>
|
||||
<a t-attf-href="/partners/#{slug(partner.assigned_partner_id)}">
|
||||
<span t-field="partner.assigned_partner_id"/>
|
||||
<span class="small"> (<t t-esc="len([p for p in partner.assigned_partner_id.implemented_partner_ids if p.website_published])"/> reference(s))</span>
|
||||
</a>
|
||||
</h4>
|
||||
<div><a t-attf-href="/partners/#{slug(partner.assigned_partner_id)}"
|
||||
t-field="partner.assigned_partner_id.image_medium"
|
||||
t-field-options='{"widget": "image", "class": "center-block"}'
|
||||
/>
|
||||
</div>
|
||||
<address class="well text-left">
|
||||
<div t-field="partner.assigned_partner_id" t-field-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["address", "website", "phone", "fax", "email"]
|
||||
}'/>
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="references" inherit_id="website_customer.details" name="Partner References">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<t t-if="implemented_partners_data">
|
||||
<template id="references_block" name="Partner References Block">
|
||||
<t t-if="any([p.website_published for p in partner.implemented_partner_ids])">
|
||||
<h3 id="references">References</h3>
|
||||
<div t-foreach="implemented_partners_data" t-as="partner_data" class="media">
|
||||
<a class="pull-left" t-attf-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data.get('image_small')}"/>
|
||||
<div t-foreach="partner.implemented_partner_ids" t-as="reference" class="media">
|
||||
<t t-if="reference.website_published">
|
||||
<a class="pull-left" t-attf-href="/customers/#{slug(reference)}">
|
||||
<span t-field="reference.image_small" t-field-options='{"widget": "image", "class": "center-block"}'/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/customers/#{ slug([partner_data.get('id'), partner_data.get('name')]) }">
|
||||
<t t-if="partner_data.get('parent_id')"><span t-esc="partner_data.get('parent_id')[1]"/></t> <span t-esc="partner_data.get('name')"/>
|
||||
<a class="media-heading" t-attf-href="/customers/#{slug(reference)}">
|
||||
<span t-field="reference.self"/>
|
||||
</a>
|
||||
<div t-if="partner_data.get('website_short_description')" t-raw="partner_data.get('website_short_description')"/>
|
||||
<div t-field='reference.website_short_description'/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -140,7 +140,7 @@ class website_event(http.Controller):
|
|||
'country_id': ("all", _("All Countries"))
|
||||
})
|
||||
|
||||
step = 5
|
||||
step = 10 # Number of events per page
|
||||
event_count = event_obj.search(
|
||||
request.cr, request.uid, dom_without("none"), count=True,
|
||||
context=request.context)
|
||||
|
|
|
@ -50,7 +50,6 @@ class website_event(website_event):
|
|||
|
||||
def _add_event(self, event_name="New Event", context={}, **kwargs):
|
||||
try:
|
||||
print kwargs
|
||||
dummy, res_id = request.registry.get('ir.model.data').get_object_reference(request.cr, request.uid, 'event_sale', 'product_product_event')
|
||||
context['default_event_ticket_ids'] = [[0,0,{
|
||||
'name': _('Subscription'),
|
||||
|
|
|
@ -18,19 +18,17 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import collections
|
||||
|
||||
import datetime
|
||||
import re
|
||||
|
||||
import pytz
|
||||
import werkzeug.utils
|
||||
|
||||
import openerp
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.controllers.main import Website as controllers
|
||||
import datetime
|
||||
|
||||
import re
|
||||
import werkzeug.utils
|
||||
|
||||
controllers = controllers()
|
||||
import pytz
|
||||
from pytz import timezone
|
||||
|
||||
class website_event(http.Controller):
|
||||
@http.route(['''/event/<model("event.event"):event>/track/<model("event.track", "[('event_id','=',event[0])]"):track>'''], type='http', auth="public", website=True)
|
||||
|
@ -79,24 +77,21 @@ class website_event(http.Controller):
|
|||
# TODO: not implemented
|
||||
@http.route(['''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/agenda'''], type='http', auth="public", website=True)
|
||||
def event_agenda(self, event, tag=None, **post):
|
||||
comp = lambda x: (x.date, bool(x.location_id))
|
||||
event.track_ids.sort(lambda x,y: cmp(comp(x), comp(y)))
|
||||
days_tracks = collections.defaultdict(lambda: [])
|
||||
for track in sorted(event.track_ids, key=lambda x: (x.date, bool(x.location_id))):
|
||||
if not track.date: continue
|
||||
days_tracks[track.date[:10]].append(track)
|
||||
|
||||
days = {}
|
||||
days_nbr = {}
|
||||
for track in event.track_ids:
|
||||
if not track.date: continue
|
||||
days.setdefault(track.date[:10], [])
|
||||
days[track.date[:10]].append(track)
|
||||
|
||||
for d in days:
|
||||
days_nbr[d] = len(days[d])
|
||||
days[d] = self._prepare_calendar(event, days[d])
|
||||
days_tracks_count = {}
|
||||
for day, tracks in days_tracks.iteritems():
|
||||
days_tracks_count[day] = len(tracks)
|
||||
days[day] = self._prepare_calendar(event, tracks)
|
||||
|
||||
return request.website.render("website_event_track.agenda", {
|
||||
'event': event,
|
||||
'days': days,
|
||||
'days_nbr': days_nbr,
|
||||
'days_nbr': days_tracks_count,
|
||||
'tag': tag
|
||||
})
|
||||
|
||||
|
|
|
@ -53,7 +53,9 @@
|
|||
<input type="text" class="form-control" placeholder="Filter Tracks..." id="event_track_search"/>
|
||||
</div>
|
||||
</section>
|
||||
<section class="container" t-foreach="days.keys()" t-as="day">
|
||||
<t t-set="dayslist" t-value="days.keys()"/>
|
||||
<t t-set="dayslist2" t-value="dayslist.sort()"/> <!-- display days in the right order -->
|
||||
<section class="container" t-foreach="dayslist" t-as="day">
|
||||
<t t-set="locations" t-value="days[day]['locations']"/>
|
||||
<t t-set="dates" t-value="days[day]['dates']"/>
|
||||
<h3 class="page-header mt0">
|
||||
|
@ -222,7 +224,7 @@
|
|||
<b>Date</b><br/>
|
||||
<span t-field="track.date" t-field-options='{"hide_seconds":"True"}'/><br/>
|
||||
<b>Duration</b><br/>
|
||||
<span t-esc="'%.2f' % (track.duration)"/> hours<br/>
|
||||
<span t-field="track.duration" t-field-options="{"widget": "duration", "unit": "hour"}"/><br/>
|
||||
<b>Location</b><br/>
|
||||
<span t-field="track.location_id"/><br/>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from datetime import datetime
|
||||
import werkzeug.urls
|
||||
import werkzeug.wrappers
|
||||
import simplejson
|
||||
|
||||
from openerp import tools
|
||||
|
@ -73,7 +74,7 @@ class WebsiteForum(http.Controller):
|
|||
forums = Forum.browse(cr, uid, obj_ids, context=context)
|
||||
return request.website.render("website_forum.forum_all", {'forums': forums})
|
||||
|
||||
@http.route('/forum/new', type='http', auth="user", website=True)
|
||||
@http.route('/forum/new', type='http', auth="user", methods=['POST'], website=True)
|
||||
def forum_create(self, forum_name="New Forum", **kwargs):
|
||||
forum_id = request.registry['forum.forum'].create(request.cr, request.uid, {
|
||||
'name': forum_name,
|
||||
|
@ -87,14 +88,15 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
@http.route(['/forum/<model("forum.forum"):forum>',
|
||||
'/forum/<model("forum.forum"):forum>/page/<int:page>',
|
||||
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions'''
|
||||
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions''',
|
||||
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions/page/<int:page>''',
|
||||
], type='http', auth="public", website=True)
|
||||
def questions(self, forum, tag=None, page=1, filters='all', sorting='date', search='', **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
Post = request.registry['forum.post']
|
||||
user = request.registry['res.users'].browse(cr, uid, uid, context=context)
|
||||
|
||||
domain = [('forum_id', '=', forum.id), ('parent_id', '=', False)]
|
||||
domain = [('forum_id', '=', forum.id), ('parent_id', '=', False), ('state', '=', 'active')]
|
||||
if search:
|
||||
domain += ['|', ('name', 'ilike', search), ('content', 'ilike', search)]
|
||||
if tag:
|
||||
|
@ -110,12 +112,28 @@ class WebsiteForum(http.Controller):
|
|||
order = 'child_count desc'
|
||||
elif sorting == 'vote':
|
||||
order = 'vote_count desc'
|
||||
else:
|
||||
sorting = 'date'
|
||||
elif sorting == 'date':
|
||||
order = 'write_date desc'
|
||||
else:
|
||||
sorting = 'creation'
|
||||
order = 'create_date desc'
|
||||
|
||||
question_count = Post.search(cr, uid, domain, count=True, context=context)
|
||||
pager = request.website.pager(url="/forum/%s" % slug(forum), total=question_count, page=page, step=self._post_per_page, scope=self._post_per_page)
|
||||
if tag:
|
||||
url = "/forum/%s/%s/questions" % (slug(forum), slug(tag))
|
||||
else:
|
||||
url = "/forum/%s" % slug(forum)
|
||||
|
||||
url_args = {}
|
||||
if search:
|
||||
url_args['search'] = search
|
||||
if filters:
|
||||
url_args['filters'] = filters
|
||||
if sorting:
|
||||
url_args['sorting'] = sorting
|
||||
pager = request.website.pager(url=url, total=question_count, page=page,
|
||||
step=self._post_per_page, scope=self._post_per_page,
|
||||
url_args=url_args)
|
||||
|
||||
obj_ids = Post.search(cr, uid, domain, limit=self._post_per_page, offset=pager['offset'], order=order, context=context)
|
||||
question_ids = Post.browse(cr, uid, obj_ids, context=context)
|
||||
|
@ -220,7 +238,7 @@ class WebsiteForum(http.Controller):
|
|||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'favourite_ids': favourite_ids}, context=request.context)
|
||||
return favourite
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/ask_for_close', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/ask_for_close', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_ask_for_close(self, forum, question, **post):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
|
||||
if not check_res[0]:
|
||||
|
@ -262,7 +280,7 @@ class WebsiteForum(http.Controller):
|
|||
}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/reopen', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/reopen', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_reopen(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
|
||||
if not check_res[0]:
|
||||
|
@ -271,7 +289,7 @@ class WebsiteForum(http.Controller):
|
|||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'state': 'active'}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/delete', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/delete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_delete(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
|
@ -280,7 +298,7 @@ class WebsiteForum(http.Controller):
|
|||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': False}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/undelete', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/undelete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_undelete(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
|
@ -339,7 +357,7 @@ class WebsiteForum(http.Controller):
|
|||
request.registry['forum.post'].write(cr, uid, [post.id], {'is_correct': not post.is_correct}, context=context)
|
||||
return not post.is_correct
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/delete', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/delete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def post_delete(self, forum, post, **kwargs):
|
||||
check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
|
@ -419,14 +437,16 @@ class WebsiteForum(http.Controller):
|
|||
# User
|
||||
# --------------------------------------------------
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/users', type='http', auth="public", website=True)
|
||||
@http.route(['/forum/<model("forum.forum"):forum>/users',
|
||||
'/forum/<model("forum.forum"):forum>/users/page/<int:page>'],
|
||||
type='http', auth="public", website=True)
|
||||
def users(self, forum, page=1, **searches):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
User = request.registry['res.users']
|
||||
|
||||
step = 30
|
||||
tag_count = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], count=True, context=context)
|
||||
pager = request.website.pager(url="/forum/users", total=tag_count, page=page, step=step, scope=30)
|
||||
pager = request.website.pager(url="/forum/%s/users" % slug(forum), total=tag_count, page=page, step=step, scope=30)
|
||||
|
||||
obj_ids = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], limit=step, offset=pager['offset'], order='karma DESC', context=context)
|
||||
users = User.browse(cr, SUPERUSER_ID, obj_ids, context=context)
|
||||
|
@ -452,6 +472,17 @@ class WebsiteForum(http.Controller):
|
|||
return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), partner.user_ids[0].id))
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
@http.route(['/forum/user/<int:user_id>/avatar'], type='http', auth="public", website=True)
|
||||
def user_avatar(self, user_id=0, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
response = werkzeug.wrappers.Response()
|
||||
User = request.registry['res.users']
|
||||
Website = request.registry['website']
|
||||
user = User.browse(cr, SUPERUSER_ID, user_id, context=context)
|
||||
if not user.exists() or (user_id != request.session.uid and user.karma < 1):
|
||||
return Website._image_placeholder(response)
|
||||
return Website._image(cr, SUPERUSER_ID, 'res.users', user.id, 'image', response)
|
||||
|
||||
@http.route(['/forum/<model("forum.forum"):forum>/user/<int:user_id>'], type='http', auth="public", website=True)
|
||||
def open_user(self, forum, user_id=0, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
|
@ -462,10 +493,9 @@ class WebsiteForum(http.Controller):
|
|||
Followers = request.registry['mail.followers']
|
||||
Data = request.registry["ir.model.data"]
|
||||
|
||||
user_id = User.search(cr, SUPERUSER_ID, [('id', '=', user_id), ('karma', '>', '1')], context=context)
|
||||
if not user_id:
|
||||
user = User.browse(cr, SUPERUSER_ID, user_id, context=context)
|
||||
if not user.exists() or (user_id != request.session.uid and user.karma < 1):
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
user = User.browse(cr, SUPERUSER_ID, user_id[0], context=context)
|
||||
|
||||
# questions and answers by user
|
||||
user_questions, user_answers = [], []
|
||||
|
@ -506,7 +536,7 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
#activity by user.
|
||||
model, comment = Data.get_object_reference(cr, uid, 'mail', 'mt_comment')
|
||||
activity_ids = Activity.search(cr, uid, [('res_id', 'in', user_post_ids), ('model', '=', 'forum.post'), ('subtype_id', '!=', comment)], context=context)
|
||||
activity_ids = Activity.search(cr, uid, [('res_id', 'in', user_post_ids), ('model', '=', 'forum.post'), ('subtype_id', '!=', comment)], order='date DESC', limit=100, context=context)
|
||||
activities = Activity.browse(cr, uid, activity_ids, context=context)
|
||||
|
||||
posts = {}
|
||||
|
@ -549,14 +579,14 @@ class WebsiteForum(http.Controller):
|
|||
})
|
||||
return request.website.render("website_forum.edit_profile", values)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/save', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/save', type='http', auth="user", methods=['POST'], website=True)
|
||||
def save_edited_profile(self, forum, user, **kwargs):
|
||||
request.registry['res.users'].write(request.cr, request.uid, [user.id], {
|
||||
'name': kwargs.get('name'),
|
||||
'website': kwargs.get('website'),
|
||||
'email': kwargs.get('email'),
|
||||
'city': kwargs.get('city'),
|
||||
'country_id': kwargs.get('country'),
|
||||
'country_id': int(kwargs.get('country')),
|
||||
'website_description': kwargs.get('description'),
|
||||
}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), user.id))
|
||||
|
@ -570,6 +600,7 @@ class WebsiteForum(http.Controller):
|
|||
Badge = request.registry['gamification.badge']
|
||||
badge_ids = Badge.search(cr, SUPERUSER_ID, [('challenge_ids.category', '=', 'forum')], context=context)
|
||||
badges = Badge.browse(cr, uid, badge_ids, context=context)
|
||||
badges = sorted(badges, key=lambda b: b.stat_count_distinct, reverse=True)
|
||||
values = self._prepare_forum_values(forum=forum, searches={'badges': True})
|
||||
values.update({
|
||||
'badges': badges,
|
||||
|
@ -590,7 +621,7 @@ class WebsiteForum(http.Controller):
|
|||
# Messaging
|
||||
# --------------------------------------------------
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", methods=['POST'], website=True)
|
||||
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
|
||||
body = comment.body
|
||||
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
|
||||
|
@ -600,7 +631,7 @@ class WebsiteForum(http.Controller):
|
|||
return self.post_comment(forum, answer, comment=html2plaintext(body))
|
||||
return self.post_new(forum, question, content=body)
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", methods=['POST'], website=True)
|
||||
def convert_answer_to_comment(self, forum, post, **kwarg):
|
||||
values = {
|
||||
'comment': html2plaintext(post.content),
|
||||
|
|
|
@ -78,16 +78,16 @@
|
|||
<field name="target_goal">10</field>
|
||||
</record>
|
||||
|
||||
<!-- Pundit: 10 comments with at least score of 10 -->
|
||||
<!-- Pundit: 10 answers with at least score of 10 -->
|
||||
<record id="badge_25" model="gamification.badge">
|
||||
<field name="name">Pundit</field>
|
||||
<field name="description">Left comments with score of 10 or more</field>
|
||||
<field name="description">Left 10 answers with score of 10 or more</field>
|
||||
<field name="level">silver</field>
|
||||
<field name="rule_auth">nobody</field>
|
||||
</record>
|
||||
<record model="gamification.goal.definition" id="definition_pundit">
|
||||
<field name="name">Pundit</field>
|
||||
<field name="description">Post 10 comments with score of 10 or more</field>
|
||||
<field name="description">Post 10 answers with score of 10 or more</field>
|
||||
<field name="display_mode">boolean</field>
|
||||
<field name="condition">higher</field>
|
||||
<field name="model_id" eval="ref('website_forum.model_forum_post')"/>
|
||||
|
|
|
@ -372,7 +372,7 @@
|
|||
<field name="computation_mode">count</field>
|
||||
<field name="display_mode">boolean</field>
|
||||
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
|
||||
<field name="domain">[('parent_id', '=', False), ('is_correct', '=', True)]</field>
|
||||
<field name="domain">[('parent_id', '=', False), ('has_validated_answer', '=', True)]</field>
|
||||
<field name="condition">higher</field>
|
||||
<field name="batch_mode">True</field>
|
||||
<field name="batch_distinctive_field" eval="ref('website_forum.field_forum_post_create_uid')" />
|
||||
|
|
|
@ -70,9 +70,6 @@
|
|||
<record id="reason_4" model="forum.post.reason">
|
||||
<field name="name">not a real question</field>
|
||||
</record>
|
||||
<record id="reason_5" model="forum.post.reason">
|
||||
<field name="name">already answered and an answer was accepted</field>
|
||||
</record>
|
||||
<record id="reason_6" model="forum.post.reason">
|
||||
<field name="name">not relevant or out dated</field>
|
||||
</record>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import openerp
|
||||
from urlparse import urljoin
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.website.models.website import slug
|
||||
from openerp.osv import osv, fields
|
||||
|
@ -269,10 +270,14 @@ class Post(osv.Model):
|
|||
return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]]}
|
||||
|
||||
def set_viewed(self, cr, uid, ids, context=None):
|
||||
for post in self.browse(cr, uid, ids, context=context):
|
||||
self.write(cr, uid, [post.id], {'views': post.views + 1}, context=context)
|
||||
cr.execute("""UPDATE forum_post SET views = views+1 WHERE id IN %s""", (tuple(ids),))
|
||||
return True
|
||||
|
||||
def _get_access_link(self, cr, uid, mail, partner, context=None):
|
||||
post = self.pool['forum.post'].browse(cr, uid, mail.res_id, context=context)
|
||||
res_id = post.parent_id and "%s#answer-%s" % (post.parent_id.id, post.id) or post.id
|
||||
return "/forum/%s/question/%s" % (post.forum_id.id, res_id)
|
||||
|
||||
|
||||
class PostReason(osv.Model):
|
||||
_name = "forum.post.reason"
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class Users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
init_res = super(Users, self).__init__(pool, cr)
|
||||
self.SELF_WRITEABLE_FIELDS = list(set(
|
||||
self.SELF_WRITEABLE_FIELDS + \
|
||||
['country_id', 'city', 'website', 'website_description']))
|
||||
return init_res
|
||||
|
||||
def _get_user_badge_level(self, cr, uid, ids, name, args, context=None):
|
||||
"""Return total badge per level of users"""
|
||||
result = dict.fromkeys(ids, False)
|
||||
|
|
|
@ -24,16 +24,25 @@
|
|||
.question .badge-active {
|
||||
background-color: #428bca;
|
||||
}
|
||||
.question img {
|
||||
max-width: 600px;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.forum_answer img {
|
||||
max-width: 600px;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
img.img-avatar {
|
||||
max-width: 50px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.oe_grey {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.img-avatar {
|
||||
max-width: 50px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.badge-gold {
|
||||
color: #ffcc00;
|
||||
}
|
||||
|
@ -94,3 +103,7 @@ a.no-decoration {
|
|||
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
||||
height: 1.2em !important;
|
||||
}
|
||||
|
||||
button.btn-link.text-muted {
|
||||
color: #999999;
|
||||
}
|
||||
|
|
|
@ -19,14 +19,23 @@
|
|||
margin-left: 4px
|
||||
.badge-active
|
||||
background-color: #428bca
|
||||
img
|
||||
max-width: 600px
|
||||
height: auto !important
|
||||
|
||||
.forum_answer
|
||||
img
|
||||
max-width: 600px
|
||||
height: auto !important
|
||||
|
||||
img.img-avatar
|
||||
max-width: 50px
|
||||
margin-right: 10px
|
||||
|
||||
|
||||
.oe_grey
|
||||
background-color: #eeeeee
|
||||
|
||||
.img-avatar
|
||||
max-width: 50px
|
||||
margin-right: 10px
|
||||
|
||||
.badge-gold
|
||||
color: #ffcc00
|
||||
|
||||
|
@ -74,3 +83,6 @@ a.no-decoration
|
|||
.text-tags .text-tag .text-button
|
||||
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important
|
||||
height: 1.2em !important
|
||||
|
||||
button.btn-link.text-muted
|
||||
color: #999
|
||||
|
|
|
@ -3,7 +3,7 @@ $(document).ready(function () {
|
|||
$('.vote_up ,.vote_down').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.attr('href'), 'call', {})
|
||||
openerp.jsonRpc($link.data('href'), 'call', {})
|
||||
.then(function (data) {
|
||||
if (data['error']){
|
||||
if (data['error'] == 'own_post'){
|
||||
|
@ -47,7 +47,7 @@ $(document).ready(function () {
|
|||
$('.accept_answer').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
|
||||
openerp.jsonRpc($link.data('href'), 'call', {}).then(function (data) {
|
||||
if (data['error']) {
|
||||
if (data['error'] == 'anonymous_user'){
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="correct_answer_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
|
@ -83,7 +83,7 @@ $(document).ready(function () {
|
|||
$('.favourite_question').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
|
||||
openerp.jsonRpc($link.data('href'), 'call', {}).then(function (data) {
|
||||
if (data) {
|
||||
$link.addClass("forum_favourite_question")
|
||||
} else {
|
||||
|
@ -96,7 +96,7 @@ $(document).ready(function () {
|
|||
$('.comment_delete').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
|
||||
openerp.jsonRpc($link.data('href'), 'call', {}).then(function (data) {
|
||||
$link.parents('.comment').first().remove();
|
||||
});
|
||||
return true;
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- helper -->
|
||||
<template id="link_button">
|
||||
<form method="POST" t-att-action="url">
|
||||
<button t-attf-class="fa btn-link #{classes}">
|
||||
<t t-esc="label"/></button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<!-- Page Index -->
|
||||
<template id="header" name="Forum Index">
|
||||
<t t-call="website.layout">
|
||||
|
@ -223,6 +231,7 @@
|
|||
<t t-if="filters == 'followed'">Followed</t>
|
||||
<t t-if="tag"><span t-field="tag.name"/></t>
|
||||
<t t-if="sorting == 'date'"> by activity date</t>
|
||||
<t t-if="sorting == 'creation'"> by creation date</t>
|
||||
<t t-if="sorting == 'answered'"> by most answered</t>
|
||||
<t t-if="sorting == 'vote'"> by most voted</t>
|
||||
<b class="caret"/>
|
||||
|
@ -246,6 +255,9 @@
|
|||
<li t-att-class="sorting == 'date' and 'active' or '' ">
|
||||
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='date')">Last activity date</a>
|
||||
</li>
|
||||
<li t-att-class="sorting == 'creation' and 'active' or '' ">
|
||||
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='creation')">Newest</a>
|
||||
</li>
|
||||
<li t-att-class="sorting == 'answered' and 'active' or '' ">
|
||||
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='answered')">Most answered</a>
|
||||
</li>
|
||||
|
@ -389,10 +401,10 @@
|
|||
<template id="vote">
|
||||
<div t-attf-class="box oe_grey">
|
||||
<a t-attf-class="vote_up fa fa-thumbs-up no-decoration #{post.user_vote == 1 and 'text-success' or ''}"
|
||||
t-attf-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/upvote"/>
|
||||
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/upvote"/>
|
||||
<span id="vote_count" t-esc="post.vote_count"/>
|
||||
<a t-attf-class="vote_down fa fa-thumbs-down no-decoration #{post.user_vote == -1 and 'text-warning' or ''}"
|
||||
t-attf-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/downvote"/>
|
||||
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/downvote"/>
|
||||
<div t-if="vote_count > 1" class="subtitle">
|
||||
votes
|
||||
</div>
|
||||
|
@ -414,7 +426,7 @@
|
|||
<span t-field="question.views"/> Views
|
||||
</div>
|
||||
<div class="mt4">
|
||||
<a t-attf-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}/toggle_favourite"
|
||||
<a t-attf-data-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}/toggle_favourite"
|
||||
t-attf-class="favourite_question no-decoration fa fa-2x fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -424,17 +436,23 @@
|
|||
<span t-if="not question.active"><b> [Deleted]</b></span>
|
||||
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
|
||||
</h1>
|
||||
<div class="alert alert-info" t-if="question.state == 'close'">
|
||||
<p class="mt32 mb16 text-center">
|
||||
<b>The question has been closed for reason: <i t-esc="question.closed_reason_id.name"/>
|
||||
<br/>
|
||||
<t t-if="question.closed_uid">
|
||||
<i>by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ slug(question.closed_uid) }" t-field="question.closed_uid"/> </i>
|
||||
</t>
|
||||
on <span t-field="question.closed_date"/></b>
|
||||
<div class="alert alert-info text-center" t-if="question.state == 'close'">
|
||||
<p class="mt16">
|
||||
<b>The question has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
|
||||
</p>
|
||||
<div t-if="question.state == 'close' and user.karma>=500" class="mb24 text-center">
|
||||
<a class="fa fa-arrow-right" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/reopen"> Reopen</a>
|
||||
<t t-if="question.closed_uid">
|
||||
<b>by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.closed_uid.id }"
|
||||
t-field="question.closed_uid"
|
||||
t-field-options='{"widget": "contact", "fields": ["name"]}'
|
||||
style="display: inline-block;"/></b>
|
||||
</t>
|
||||
<b>on <span t-field="question.closed_date"/></b>
|
||||
<div t-if="question.state == 'close' and user.karma>=500" class="mt16 mb24 text-center">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/>
|
||||
<t t-set="label" t-value="'Reopen'"/>
|
||||
<t t-set="classes" t-value="'fa-arrow-right'"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<t t-raw="question.content"/>
|
||||
|
@ -454,30 +472,51 @@
|
|||
</a>
|
||||
</li>
|
||||
<li t-if="question.state != 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
||||
<a class="text-muted fa fa-times" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/ask_for_close"> Close</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/>
|
||||
<t t-set="label" t-value="'Close'"/>
|
||||
<t t-set="classes" t-vaoue="'text-muted fa-times'"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="question.state == 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
||||
<a class="text-muted fa fa-undo" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/reopen"> Reopen</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/>
|
||||
<t t-set="label" t-value="'Reopen'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-undo'"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="(user.id == question.create_uid.id and can_edit_own) or can_edit_all">
|
||||
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{ slug(forum) }/post/#{slug(question)}/edit"> Edit</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/>
|
||||
<t t-set="label" t-value="'Edit'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-edit'"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
|
||||
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/delete"> Delete</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/>
|
||||
<t t-set="label" t-value="'Delete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="not question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
|
||||
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/undelete"> Undelete</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/>
|
||||
<t t-set="label" t-value="'Undelete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<span t-field="question.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
||||
<img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{question.create_uid.id}/avatar"/>
|
||||
<div>
|
||||
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
|
||||
t-field="question.create_uid"
|
||||
t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
|
||||
style="display: inline-block;"/>
|
||||
<div t-field="question.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
|
||||
<span class="text-muted">Asked on <span t-field="question.create_date" t-field-options='{"format":"short"}'/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -497,7 +536,7 @@
|
|||
</t>
|
||||
<div class="text-muted mt8">
|
||||
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'}"
|
||||
t-attf-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
|
||||
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: 95px;" class="clearfix">
|
||||
|
@ -513,13 +552,21 @@
|
|||
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit"> Edit</a>
|
||||
</li>
|
||||
<li t-if="(user.id == answer.create_uid.id and can_unlink_own) or can_unlink_all">
|
||||
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/delete"> Delete</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
|
||||
<t t-set="label" t-value="'Delete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="user.id == answer.create_uid.id">
|
||||
<a class="text-muted fa fa-magic" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/convert_to_comment"> Convert as a comment</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
|
||||
<t t-set="label" t-value="'Convert as a comment'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-magic'"/>
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
<span t-field="answer.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
||||
<img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{answer.create_uid.id}/avatar"/>
|
||||
<div>
|
||||
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ answer.create_uid.id }"
|
||||
t-field="answer.create_uid"
|
||||
|
@ -552,15 +599,18 @@
|
|||
<div t-foreach="reversed(object.website_message_ids)" t-as="message" class="comment oe_comment_grey">
|
||||
<small class="text-muted">
|
||||
<button type="button" t-if="user.partner_id.id == message.author_id.id and user.karma>=750"
|
||||
t-attf-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
|
||||
t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
|
||||
class="close comment_delete">&times;</button>
|
||||
<span t-field="message.body"/>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
|
||||
<t t-set="label" t-value="'Convert as an answer'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-magic pull-right'"/>
|
||||
</t>
|
||||
<a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
|
||||
t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
|
||||
style="display: inline-block;"/>
|
||||
on <span t-field="message.date" t-field-options='{"format":"short"}'/>
|
||||
<a class="fa fa-magic text-muted pull-right"
|
||||
t-attf-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/convert_to_answer">Convert as an answer</a>
|
||||
</small>
|
||||
</div>
|
||||
<div class="css_editable_mode_hidden">
|
||||
|
@ -650,7 +700,7 @@
|
|||
</h4>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 mt16" t-foreach="users" t-as="user">
|
||||
<span t-field="user.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
||||
<img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{user.id}/avatar"/>
|
||||
<div>
|
||||
<a t-attf-href="/forum/#{slug(forum)}/user/#{user.id}" t-field="user.name"/>
|
||||
</div>
|
||||
|
@ -661,9 +711,12 @@
|
|||
|
||||
<template id="users">
|
||||
<t t-call="website_forum.header">
|
||||
<div class="row">
|
||||
<div t-foreach="users" t-as="user" class="col-sm-4">
|
||||
<span t-field="user.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
||||
<t t-foreach="users" t-as="user">
|
||||
<t t-if="user_index % 3 == 0">
|
||||
<div class="row"></div>
|
||||
</t>
|
||||
<div class="col-sm-4">
|
||||
<img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{user.id}/avatar"/>
|
||||
<div>
|
||||
<a t-attf-href="/forum/#{slug(forum)}/user/#{user.id}" t-field="user.name"/>
|
||||
<t t-if="user.country_id">
|
||||
|
@ -683,7 +736,7 @@
|
|||
<t t-raw="0"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<div class="pull-left">
|
||||
<t t-call="website.pager"/>
|
||||
</div>
|
||||
|
@ -694,7 +747,7 @@
|
|||
<t t-call="website_forum.header">
|
||||
<h3>Edit Profile </h3>
|
||||
<div class="col-md-2">
|
||||
<span t-field="user.image" t-field-options='{"widget": "image", "class": "img img-responsive img-circle"}'/>
|
||||
<img class="img img-responsive img-circle" t-attf-src="/forum/user/#{user.id}/avatar"/>
|
||||
</div>
|
||||
<form t-attf-action="/forum/#{slug(forum)}/user/#{slug(user)}/save" method="post" role="form" class="form-horizontal">
|
||||
<input name="user_id" t-att-value="user.id" type="hidden"/>
|
||||
|
@ -719,7 +772,7 @@
|
|||
<select class="form-control" name="country">
|
||||
<option value="">Country...</option>
|
||||
<t t-foreach="countries or []" t-as="country">
|
||||
<option t-att-value="country.id" t-att-selected="country.id == user.partner_id.country.id"><t t-esc="country.name"/></option>
|
||||
<option t-att-value="country.id" t-att-selected="country.id == user.partner_id.country_id.id"><t t-esc="country.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -744,8 +797,7 @@
|
|||
</h1>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<span t-field="user.image"
|
||||
t-field-options='{"widget": "image", "class": "img img-responsive img-circle"}'/>
|
||||
<img class="img img-responsive img-circle" t-attf-src="/forum/user/#{user.id}/avatar"/>
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<table class="table table-condensed">
|
||||
|
|
|
@ -28,7 +28,7 @@ class google_map(http.Controller):
|
|||
return partner_obj.google_map_json(request.cr, openerp.SUPERUSER_ID,
|
||||
partner_ids, request.context)
|
||||
|
||||
@http.route(['/google_map/set_partner_position'], type='http', auth="public", website=True)
|
||||
@http.route(['/google_map/set_partner_position'], type='http', methods=['POST'], auth="public", website=True)
|
||||
def google_map_set_partner_position(self, *arg, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from openerp.addons.web.http import request
|
|||
|
||||
class website_hr(http.Controller):
|
||||
|
||||
@http.route(['/page/website.aboutus'], type='http', auth="public", website=True)
|
||||
@http.route(['/page/website.aboutus', '/page/aboutus'], type='http', auth="public", website=True)
|
||||
def blog(self, **post):
|
||||
hr_obj = request.registry['hr.employee']
|
||||
employee_ids = hr_obj.search(request.cr, request.uid, [('website_published', '=', True)],
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website_partner.controllers import main as website_partner
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import werkzeug.urls
|
||||
|
@ -39,7 +38,7 @@ class WebsiteMembership(http.Controller):
|
|||
current_country = None
|
||||
|
||||
# base domain for groupby / searches
|
||||
base_line_domain = [("partner.website_published", "=", True),('state', 'in', ['free', 'paid'])]
|
||||
base_line_domain = [("partner.website_published", "=", True), ('state', 'in', ['free', 'paid'])]
|
||||
if membership_id:
|
||||
base_line_domain.append(('membership_id', '=', membership_id))
|
||||
membership = product_obj.browse(cr, uid, membership_id, context=context)
|
||||
|
@ -76,12 +75,10 @@ class WebsiteMembership(http.Controller):
|
|||
membership_line_ids = membership_line_obj.search(cr, uid, line_domain, context=context)
|
||||
membership_lines = membership_line_obj.browse(cr, uid, membership_line_ids, context=context)
|
||||
membership_lines.sort(key=lambda x: x.membership_id.website_sequence)
|
||||
partner_ids = [m.partner and m.partner.id for m in membership_lines]
|
||||
partner_ids = [m.partner.id for m in membership_lines]
|
||||
google_map_partner_ids = ",".join(map(str, partner_ids))
|
||||
|
||||
partners_data = {}
|
||||
for partner in partner_obj.read(cr, openerp.SUPERUSER_ID, partner_ids, request.website.get_partner_white_list_fields(), context=context):
|
||||
partners_data[partner.get("id")] = partner
|
||||
partners = dict((p.id, p) for p in partner_obj.browse(request.cr, SUPERUSER_ID, partner_ids, request.context))
|
||||
|
||||
# format domain for group_by and memberships
|
||||
membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], order="website_sequence", context=context)
|
||||
|
@ -91,7 +88,7 @@ class WebsiteMembership(http.Controller):
|
|||
pager = request.website.pager(url="/members", total=len(membership_line_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
|
||||
|
||||
values = {
|
||||
'partners_data': partners_data,
|
||||
'partners': partners,
|
||||
'membership_lines': membership_lines,
|
||||
'memberships': memberships,
|
||||
'membership': membership,
|
||||
|
@ -105,11 +102,15 @@ class WebsiteMembership(http.Controller):
|
|||
}
|
||||
return request.website.render("website_membership.index", values)
|
||||
|
||||
@http.route(['/members/<int:partner_id>', '/members/<partner_name>-<int:partner_id>'], type='http', auth="public", website=True)
|
||||
def partners_ref(self, partner_id, **post):
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
values = website_partner.get_partner_template_value(partner)
|
||||
if not values:
|
||||
return self.members(**post)
|
||||
values['main_object'] = values['partner']
|
||||
return request.website.render("website_membership.partner", values)
|
||||
# Do not use semantic controller due to SUPERUSER_ID
|
||||
@http.route(['/members/<partner_id>'], type='http', auth="public", website=True)
|
||||
def partners_detail(self, partner_id, **post):
|
||||
mo = re.search('-([-0-9]+)$', str(partner_id))
|
||||
if mo:
|
||||
partner_id = int(mo.group(1))
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
if partner.exists() and partner.website_published:
|
||||
values = {}
|
||||
values['main_object'] = values['partner'] = partner
|
||||
return request.website.render("website_membership.partner", values)
|
||||
return self.customers(**post)
|
||||
|
|
|
@ -59,14 +59,17 @@
|
|||
<t t-set="current_membership_id" t-value="membership_line_id.membership_id.id"/>
|
||||
<h3 class="text-center"><span t-field="membership_line_id.membership_id"/></h3>
|
||||
</t>
|
||||
<t t-set="partner_data" t-value="partners_data[membership_line_id.partner.id]"/>
|
||||
<t t-set="partner" t-value="partners[membership_line_id.partner.id]"/>
|
||||
<div class="media">
|
||||
<a class="pull-left" t-attf-href="/members/#{ slug([partner_data.get('id'), partner_data.get('name')]) }">
|
||||
<img class="media-object" t-attf-src="data:image/png;base64,#{partner_data.get('image_small')}"/>
|
||||
</a>
|
||||
<a class="pull-left" t-attf-href="/members/#{slug(partner)}"
|
||||
t-field="partner.image_small"
|
||||
t-field-options='{"widget": "image", "class": "media-object"}'
|
||||
></a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-attf-href="/members/#{ slug([partner_data.get('id'), partner_data.get('name')]) }"><t t-if="partner_data.get('parent_id')"><span t-esc="partner_data.get('parent_id')[1]"/></t> <span t-esc="partner_data.get('name')"/></a>
|
||||
<div t-raw="partner_data.get('website_short_description')"/>
|
||||
<a class="media-heading" t-attf-href="/members/#{slug(partner)}">
|
||||
<span t-field="partner.display_name"/>
|
||||
</a>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
import main
|
|
@ -1,43 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
import werkzeug
|
||||
|
||||
|
||||
def get_partner_template_value(partner):
|
||||
ctx = dict(request.context, show_address=True)
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_id = partner.id
|
||||
partner_ids = partner_obj.search(request.cr, request.uid, [('id', '=', partner_id)], context=request.context)
|
||||
if not partner.exists() or not partner_ids:
|
||||
partner = None
|
||||
|
||||
partner_data = partner_obj.read(
|
||||
request.cr, openerp.SUPERUSER_ID, [partner_id], request.website.get_partner_white_list_fields(), context=ctx)[0]
|
||||
|
||||
if not partner_data["website_published"]:
|
||||
return None
|
||||
|
||||
partner_data['name_get'] = partner_obj.name_get(request.cr, openerp.SUPERUSER_ID, [partner_id],context=request.context)[0]
|
||||
|
||||
partner_data['address'] = '<br/>'.join(partner_obj.name_get(
|
||||
request.cr, openerp.SUPERUSER_ID, [partner_id],context=ctx)[0][1].split('\n')[1:])
|
||||
|
||||
values = {
|
||||
'partner': partner,
|
||||
'partner_data': partner_data,
|
||||
}
|
||||
return values
|
||||
|
||||
class WebsitePartner(http.Controller):
|
||||
@http.route(['/partners/<int:partner_id>', '/partners/<partner_name>-<int:partner_id>'], type='http', auth="public", website=True)
|
||||
def partner(self, partner_id, **post):
|
||||
""" Route for displaying a single partner / customer. """
|
||||
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
|
||||
values = get_partner_template_value(partner)
|
||||
if not values:
|
||||
raise werkzeug.exceptions.NotFound
|
||||
return request.website.render("website_partner.partner_detail", values)
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="base.main_company" model="res.company">
|
||||
<record id="base.main_partner" model="res.partner">
|
||||
<field name="website_published">True</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
import res_partner
|
||||
import res_company
|
||||
import website
|
|
@ -1,10 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class WebsiteResCompany(osv.Model):
|
||||
_inherit = 'res.company'
|
||||
_columns = {
|
||||
'website_published': fields.related('partner_id', 'website_published', string='Publish', help="Publish on the website"),
|
||||
}
|
|
@ -5,7 +5,10 @@ from openerp.osv import osv, fields
|
|||
|
||||
class WebsiteResPartner(osv.Model):
|
||||
_name = 'res.partner'
|
||||
_inherit = ['res.partner','website.seo.metadata']
|
||||
_inherit = ['res.partner', 'website.seo.metadata']
|
||||
|
||||
def _get_ids(self, cr, uid, ids, flds, args, context=None):
|
||||
return {i: i for i in ids}
|
||||
|
||||
_columns = {
|
||||
'website_published': fields.boolean(
|
||||
|
@ -16,10 +19,10 @@ class WebsiteResPartner(osv.Model):
|
|||
'website_short_description': fields.text(
|
||||
'Website artner Short Description'
|
||||
),
|
||||
# hack to allow using plain browse record in qweb views
|
||||
'self': fields.function(_get_ids, type='many2one', relation=_name),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'website_published': False
|
||||
}
|
||||
|
||||
def img(self, cr, uid, ids, field='image_small', context=None):
|
||||
return "/website/image?model=%s&field=%s&id=%s" % (self._name, field, ids[0])
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import orm
|
||||
|
||||
|
||||
class Website(orm.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
def get_partner_white_list_fields(self, cr, uid, ids, context=None):
|
||||
return ["name", "parent_id", 'website_short_description', "website_published",
|
||||
"website_description", "tel", "fax", "image", "image_small", "image_medium"]
|
|
@ -2,54 +2,33 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="partner_detail" name="Partner Details (Complex Template for Access Right)">
|
||||
<t t-if="partner" >
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="partner"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="partner"><h1 class="col-md-12 text-center" t-field="partner.name"/></t>
|
||||
<t t-if="not partner"><h1 class="col-md-12 text-center" t-esc="partner_data.get('name_get')[1]"/></t>
|
||||
<div class="col-md-4">
|
||||
<div class="text-center">
|
||||
<t t-if="partner"><img t-att-src="partner.img('image')"/></t>
|
||||
<t t-if="not partner"><img t-attf-src="data:image/png;base64,#{partner_data.get('image')}"/></t>
|
||||
<template id="partner_page" name="Partner Page">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<t t-call="website_partner.partner_detail"></t>
|
||||
</div>
|
||||
<address>
|
||||
<table style="margin: auto;" class="well">
|
||||
<colgroup>
|
||||
<col width="100"/>
|
||||
<col/>
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<t t-if="partner">
|
||||
<t t-set="address" t-value="'<br/>'.join(partner.name_get()[0][1].split('\n')[1:])"/>
|
||||
<tr t-if="address or editable"><th class="texttop">Address</th><td class="span2" t-raw="address"/></tr>
|
||||
</t>
|
||||
<tr t-if="not partner and partner_data.get('address')"><th class="texttop">Address</th><td class="span2" t-raw="partner_data.get('address')"/></tr>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<tr t-if="partner and (partner.website or editable)"><th>Website</th><td class="span2">
|
||||
<t t-if="partner.website"><span t-field="partner.website"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('website')"><th>Website</th><td class="span2"><span t-esc="partner_data.get('website')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.phone or editable)"><th>Phone</th><td class="span2">
|
||||
<t t-if="partner.phone"><span t-field="partner.phone"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('phone')"><th>Phone</th><td class="span2"><span t-esc="partner_data.get('phone')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.mobile or editable)"><th>Tel</th><td class="span2">
|
||||
<t t-if="partner.mobile"><span t-field="partner.mobile"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('mobile')"><th>Tel</th><td class="span2"><span t-esc="partner_data.get('mobile')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.fax or editable)"><th>Fax</th><td class="span2">
|
||||
<t t-if="partner.fax"><span t-field="partner.fax"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('fax')"><th>Fax</th><td class="span2"><span t-esc="partner_data.get('fax')"/></td></tr>
|
||||
|
||||
<tr t-if="partner and (partner.email or editable)"><th>Email</th><td class="span2">
|
||||
<t t-if="partner.email"><span t-field="partner.email"/></t></td></tr>
|
||||
<tr t-if="partner_data.get('email')"><th>Email</th><td class="span2"><span t-esc="partner_data.get('email')"/></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<template id="partner_detail" name="Partner Details">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="partner"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
</t>
|
||||
<h1 class="col-md-12 text-center" id="partner_name" t-field="partner.display_name"/>
|
||||
<div class="col-md-4">
|
||||
<div t-field="partner.image" t-field-options='{"widget": "image", "class": "center-block mb16"}'/>
|
||||
<address class="well">
|
||||
<div t-field="partner.self" t-field-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["address", "website", "phone", "fax", "email"]
|
||||
}'/>
|
||||
</address>
|
||||
<t t-raw="left_column or ''"/>
|
||||
</div>
|
||||
|
@ -61,9 +40,6 @@
|
|||
<div class="css_non_editable_mode_hidden" t-field="partner.website_short_description"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="not partner">
|
||||
<div class="col-md-8 mt32" t-raw="partner_data.get('website_description')"/>
|
||||
</t>
|
||||
<t t-raw="right_column or ''"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -64,7 +64,7 @@ class sale_quote(http.Controller):
|
|||
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
attachments=sign and [('signature.png', sign)] or []
|
||||
attachments=sign and [('signature.png', sign.decode('base64'))] or []
|
||||
order_obj.signal_order_confirm(request.cr, SUPERUSER_ID, [order_id], context=request.context)
|
||||
message = _('Order signed by %s') % (signer,)
|
||||
self.__message_post(message, order_id, type='comment', subtype='mt_comment', attachments=attachments)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<t t-name="website.Twitter.Tweet">
|
||||
<div class="tweet" t-attf-data-url="http://twitter.com/#{tweet.user.screen_name}/status/#{tweet.id_str}" t-attf-data-tweet-id="#{tweet.id_str}">
|
||||
<div class="left">
|
||||
<img t-att-src="tweet.user.profile_image_url"/>
|
||||
<img t-att-src="tweet.user.profile_image_url_https"/>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="top">
|
||||
|
|
|
@ -5,8 +5,7 @@ import logging
|
|||
import re
|
||||
import sys
|
||||
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.routing
|
||||
import werkzeug
|
||||
|
||||
import openerp
|
||||
from openerp import http
|
||||
|
@ -59,6 +58,12 @@ class ir_http(osv.AbstractModel):
|
|||
def _auth_method_user(self):
|
||||
request.uid = request.session.uid
|
||||
if not request.uid:
|
||||
if not request.params.get('noredirect'):
|
||||
query = werkzeug.url_encode({
|
||||
'redirect': request.httprequest.url,
|
||||
})
|
||||
response = werkzeug.utils.redirect('/web/login?%s' % query)
|
||||
werkzeug.exceptions.abort(response)
|
||||
raise http.SessionExpiredException("Session expired")
|
||||
|
||||
def _auth_method_none(self):
|
||||
|
|
|
@ -351,6 +351,8 @@ class ir_model_fields(osv.osv):
|
|||
raise except_orm(_('Error'), _("Model %s does not exist!") % vals['relation'])
|
||||
|
||||
if vals['model'] in self.pool:
|
||||
if vals['model'].startswith('x_') and vals['name'] == 'x_name':
|
||||
self.pool[vals['model']]._rec_name = 'x_name'
|
||||
self.pool[vals['model']].__init__(self.pool, cr)
|
||||
#Added context to _auto_init for special treatment to custom field for select_level
|
||||
ctx = dict(context,
|
||||
|
|
|
@ -836,7 +836,8 @@ class DurationConverter(osv.AbstractModel):
|
|||
v*secs_per_unit, threshold=1, locale=locale)
|
||||
if section:
|
||||
sections.append(section)
|
||||
return u' '.join(sections)
|
||||
return ' '.join(sections)
|
||||
|
||||
|
||||
class RelativeDatetimeConverter(osv.AbstractModel):
|
||||
_name = 'ir.qweb.field.relative'
|
||||
|
@ -880,6 +881,7 @@ class Contact(orm.AbstractModel):
|
|||
'fax': field_browse.fax,
|
||||
'city': field_browse.city,
|
||||
'country_id': field_browse.country_id and field_browse.country_id.name_get()[0][1],
|
||||
'website': field_browse.website,
|
||||
'email': field_browse.email,
|
||||
'fields': opf,
|
||||
'object': field_browse,
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
<div t-if="phone and 'phone' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-phone'/> <span itemprop="telephone" t-esc="phone"/></div>
|
||||
<div t-if="mobile and 'mobile' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-mobile-phone'/> <span itemprop="telephone" t-esc="mobile"/></div>
|
||||
<div t-if="fax and 'fax' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-file-text-o'/> <span itemprop="faxNumber" t-esc="fax"/></div>
|
||||
<div t-if="website and 'website' in fields" class='css_editable_mode_hidden'>
|
||||
<i t-if="not options.get('no_marker')" class='fa fa-globe'/>
|
||||
<a t-att-href="website"><span itemprop="website" t-esc="website"/></a>
|
||||
</div>
|
||||
<div t-if="email and 'email' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-envelope'/> <span itemprop="email" t-esc="email"/></div>
|
||||
</div>
|
||||
</address>
|
||||
|
|
|
@ -253,7 +253,7 @@ class view(osv.osv):
|
|||
['type', '=', view_type],
|
||||
['inherit_id', '=', False],
|
||||
]
|
||||
ids = self.search(cr, uid, domain, limit=1, order='priority', context=context)
|
||||
ids = self.search(cr, uid, domain, limit=1, context=context)
|
||||
if not ids:
|
||||
return False
|
||||
return ids[0]
|
||||
|
|
|
@ -23,6 +23,7 @@ import datetime
|
|||
from lxml import etree
|
||||
import math
|
||||
import pytz
|
||||
import urlparse
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
|
@ -509,6 +510,14 @@ class res_partner(osv.osv, format_address):
|
|||
if not parent.is_company:
|
||||
parent.write({'is_company': True})
|
||||
|
||||
def _clean_website(self, website):
|
||||
(scheme, netloc, path, params, query, fragment) = urlparse.urlparse(website)
|
||||
if not scheme:
|
||||
if not netloc:
|
||||
netloc, path = path, ''
|
||||
website = urlparse.urlunparse(('http', netloc, path, params, query, fragment))
|
||||
return website
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
@ -516,6 +525,8 @@ class res_partner(osv.osv, format_address):
|
|||
#is the same as the company of all users that inherit from this partner
|
||||
#(this is to allow the code from res_users to write to the partner!) or
|
||||
#if setting the company_id to False (this is compatible with any user company)
|
||||
if vals.get('website'):
|
||||
vals['website'] = self._clean_website(vals['website'])
|
||||
if vals.get('company_id'):
|
||||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
if partner.user_ids:
|
||||
|
@ -528,6 +539,8 @@ class res_partner(osv.osv, format_address):
|
|||
return result
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if vals.get('website'):
|
||||
vals['website'] = self._clean_website(vals['website'])
|
||||
new_id = super(res_partner, self).create(cr, uid, vals, context=context)
|
||||
partner = self.browse(cr, uid, new_id, context=context)
|
||||
self._fields_sync(cr, uid, partner, vals, context)
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
<field name="street">31 Hong Kong street</field>
|
||||
<field name="email">asusteK@yourcompany.example.com</field>
|
||||
<field name="phone">(+886) (02) 4162 2023</field>
|
||||
<field name="website">www.asustek.com</field>
|
||||
<field name="website">http://www.asustek.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_1-image.jpg"/>
|
||||
</record>
|
||||
<record id="res_partner_2" model="res.partner">
|
||||
|
@ -90,7 +90,7 @@
|
|||
<field name="street">69 rue de Namur</field>
|
||||
<field name="email">agrolait@yourcompany.example.com</field>
|
||||
<field name="phone">+32 10 588 558</field>
|
||||
<field name="website">www.agrolait.com</field>
|
||||
<field name="website">http://www.agrolait.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_2-image.jpg"/>
|
||||
</record>
|
||||
<record id="res_partner_3" model="res.partner">
|
||||
|
@ -105,7 +105,7 @@
|
|||
<field name="street">52 Chop Suey street</field>
|
||||
<field name="email">chinaexport@yourcompany.example.com</field>
|
||||
<field name="phone">+86 21 6484 5671</field>
|
||||
<field name="website">www.chinaexport.com/</field>
|
||||
<field name="website">http://www.chinaexport.com/</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_3-image.png"/>
|
||||
</record>
|
||||
|
||||
|
@ -122,7 +122,7 @@
|
|||
<field name="street">3661 Station Street</field>
|
||||
<field name="email">deltapc@yourcompany.example.com</field>
|
||||
<field name="phone">+1 510 340 2385</field>
|
||||
<field name="website">www.distribpc.com/</field>
|
||||
<field name="website">http://www.distribpc.com/</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_4-image.png"/>
|
||||
</record>
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
|||
<field name="city">Chicago</field>
|
||||
<field name="email">epic@yourcompany.example.com</field>
|
||||
<field name="phone">+1 312 349 2324</field>
|
||||
<field name="website">www.epic-tech.info//</field>
|
||||
<field name="website">http://www.epic-tech.info//</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_5-image.jpg"/>
|
||||
</record>
|
||||
|
||||
|
@ -169,7 +169,7 @@
|
|||
<field name="country_id" ref="base.uk"/>
|
||||
<field name="phone">+44 121 690 4596</field>
|
||||
<field name="email">wealthyandsons@yourcompany.example.com</field>
|
||||
<field name="website">www.wealthyandsons.com/</field>
|
||||
<field name="website">http://www.wealthyandsons.com/</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_7-image.jpg"/>
|
||||
</record>
|
||||
|
||||
|
@ -198,7 +198,7 @@
|
|||
<field name="country_id" ref="base.in"/>
|
||||
<field name="email">bestdesigners@yourcompany.example.com</field>
|
||||
<field name="phone">+91 22 3445 0349</field>
|
||||
<field name="website">www.bestdesigners.com</field>
|
||||
<field name="website">http://www.bestdesigners.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_9-image.jpg"/>
|
||||
</record>
|
||||
|
||||
|
@ -228,7 +228,7 @@
|
|||
<field name="city">Barcelona</field>
|
||||
<field name="zip">08078</field>
|
||||
<field name="phone">+34 934 340 230</field>
|
||||
<field name="website">www.lumitech.com</field>
|
||||
<field name="website">http://www.lumitech.com</field>
|
||||
<field name="email">luminous@yourcompany.example.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_11-image.png"/>
|
||||
</record>
|
||||
|
@ -245,7 +245,7 @@
|
|||
<field name="country_id" ref="base.fr"/>
|
||||
<field name="street">93, Press Avenue</field>
|
||||
<field name="email">camptocamp@yourcompany.example.com</field>
|
||||
<field name="website">www.camptocamp.com</field>
|
||||
<field name="website">http://www.camptocamp.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_12-image.jpg"/>
|
||||
</record>
|
||||
|
||||
|
@ -260,7 +260,7 @@
|
|||
<field name="email">axelor@yourcompany.example.com</field>
|
||||
<field name="phone">+33 1 64 61 04 01</field>
|
||||
<field name="street">12 rue Albert Einstein</field>
|
||||
<field name="website">www.axelor.com/</field>
|
||||
<field name="website">http://www.axelor.com/</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_13-image.jpg"/>
|
||||
</record>
|
||||
|
||||
|
@ -336,7 +336,7 @@
|
|||
<field name="phone">+1 857 349 3049</field>
|
||||
<field name="country_id" ref="base.us"/>
|
||||
<field name="street">One Lincoln Street</field>
|
||||
<field name="website">www.think-big.com</field>
|
||||
<field name="website">http://www.think-big.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_18-image.png"/>
|
||||
</record>
|
||||
|
||||
|
@ -394,7 +394,7 @@
|
|||
<field name="zip">LE4 2BN</field>
|
||||
<field name="phone">+44 20 1294 2193</field>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field name="website">www.vicking-direct.com</field>
|
||||
<field name="website">http://www.vicking-direct.com</field>
|
||||
<field name="email">vickingdirect@yourcompany.example.com</field>
|
||||
<field name="image" type="base64" file="base/static/img/res_partner_22-image.jpg"/>
|
||||
</record>
|
||||
|
|
|
@ -3758,9 +3758,13 @@ class BaseModel(object):
|
|||
ir_values_obj.unlink(cr, uid, ir_value_ids, context=context)
|
||||
|
||||
for order, obj_name, store_ids, fields in result_store:
|
||||
if obj_name != self._name:
|
||||
if obj_name == self._name:
|
||||
effective_store_ids = list(set(store_ids) - set(ids))
|
||||
else:
|
||||
effective_store_ids = store_ids
|
||||
if effective_store_ids:
|
||||
obj = self.pool[obj_name]
|
||||
cr.execute('select id from '+obj._table+' where id IN %s', (tuple(store_ids),))
|
||||
cr.execute('select id from '+obj._table+' where id IN %s', (tuple(effective_store_ids),))
|
||||
rids = map(lambda x: x[0], cr.fetchall())
|
||||
if rids:
|
||||
obj._store_set_values(cr, uid, rids, fields, context)
|
||||
|
@ -5130,7 +5134,14 @@ class BaseModel(object):
|
|||
# shortcut read if we only want the ids
|
||||
return [{'id': id} for id in record_ids]
|
||||
|
||||
result = self.read(cr, uid, record_ids, fields, context=context)
|
||||
# read() ignores active_test, but it would forward it to any downstream search call
|
||||
# (e.g. for x2m or function fields), and this is not the desired behavior, the flag
|
||||
# was presumably only meant for the main search().
|
||||
# TODO: Move this to read() directly?
|
||||
read_ctx = dict(context or {})
|
||||
read_ctx.pop('active_test', None)
|
||||
|
||||
result = self.read(cr, uid, record_ids, fields, context=read_ctx)
|
||||
if len(result) <= 1:
|
||||
return result
|
||||
|
||||
|
|
|
@ -477,6 +477,7 @@ ALL_LANGUAGES = {
|
|||
'lo_LA': u'Lao / ພາສາລາວ',
|
||||
'lt_LT': u'Lithuanian / Lietuvių kalba',
|
||||
'lv_LV': u'Latvian / latviešu valoda',
|
||||
'mk_MK': u'Macedonian / македонски јазик',
|
||||
'ml_IN': u'Malayalam / മലയാളം',
|
||||
'mn_MN': u'Mongolian / монгол',
|
||||
'nb_NO': u'Norwegian Bokmål / Norsk bokmål',
|
||||
|
|
Loading…
Reference in New Issue