[MERGE] Forward-port saas-5 up to a5f7891
This commit is contained in:
commit
ef53a831c6
|
@ -1038,6 +1038,8 @@ class account_move_line(osv.osv):
|
||||||
all_moves = list(set(all_moves) - set(move_ids))
|
all_moves = list(set(all_moves) - set(move_ids))
|
||||||
if unlink_ids:
|
if unlink_ids:
|
||||||
if opening_reconciliation:
|
if opening_reconciliation:
|
||||||
|
raise osv.except_osv(_('Warning!'),
|
||||||
|
_('Opening Entries have already been generated. Please run "Cancel Closing Entries" wizard to cancel those entries and then run this wizard.'))
|
||||||
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
|
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
|
||||||
obj_move_rec.unlink(cr, uid, unlink_ids)
|
obj_move_rec.unlink(cr, uid, unlink_ids)
|
||||||
if len(all_moves) >= 2:
|
if len(all_moves) >= 2:
|
||||||
|
|
|
@ -141,6 +141,7 @@ class crm_phonecall(osv.osv):
|
||||||
'partner_phone' : call.partner_phone,
|
'partner_phone' : call.partner_phone,
|
||||||
'partner_mobile' : call.partner_mobile,
|
'partner_mobile' : call.partner_mobile,
|
||||||
'priority': call.priority,
|
'priority': call.priority,
|
||||||
|
'opportunity_id': call.opportunity_id and call.opportunity_id.id or False,
|
||||||
}
|
}
|
||||||
new_id = self.create(cr, uid, vals, context=context)
|
new_id = self.create(cr, uid, vals, context=context)
|
||||||
if action == 'log':
|
if action == 'log':
|
||||||
|
|
|
@ -19,11 +19,14 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
from openerp.osv import fields,osv
|
from openerp.osv import fields,osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
import openerp.addons.decimal_precision as dp
|
import openerp.addons.decimal_precision as dp
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class delivery_carrier(osv.osv):
|
class delivery_carrier(osv.osv):
|
||||||
_name = "delivery.carrier"
|
_name = "delivery.carrier"
|
||||||
_description = "Carrier"
|
_description = "Carrier"
|
||||||
|
@ -51,14 +54,24 @@ class delivery_carrier(osv.osv):
|
||||||
for carrier in self.browse(cr, uid, ids, context=context):
|
for carrier in self.browse(cr, uid, ids, context=context):
|
||||||
order_id=context.get('order_id',False)
|
order_id=context.get('order_id',False)
|
||||||
price=False
|
price=False
|
||||||
|
available = False
|
||||||
if order_id:
|
if order_id:
|
||||||
order = sale_obj.browse(cr, uid, order_id, context=context)
|
order = sale_obj.browse(cr, uid, order_id, context=context)
|
||||||
carrier_grid=self.grid_get(cr,uid,[carrier.id],order.partner_shipping_id.id,context)
|
carrier_grid=self.grid_get(cr,uid,[carrier.id],order.partner_shipping_id.id,context)
|
||||||
if carrier_grid:
|
if carrier_grid:
|
||||||
|
try:
|
||||||
price=grid_obj.get_price(cr, uid, carrier_grid, order, time.strftime('%Y-%m-%d'), context)
|
price=grid_obj.get_price(cr, uid, carrier_grid, order, time.strftime('%Y-%m-%d'), context)
|
||||||
|
available = True
|
||||||
|
except osv.except_osv, e:
|
||||||
|
# no suitable delivery method found, probably configuration error
|
||||||
|
_logger.error("Carrier %s: %s\n%s" % (carrier.name, e.name, e.value))
|
||||||
|
price = 0.0
|
||||||
else:
|
else:
|
||||||
price = 0.0
|
price = 0.0
|
||||||
res[carrier.id]=price
|
res[carrier.id] = {
|
||||||
|
'price': price,
|
||||||
|
'available': available
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
|
@ -66,7 +79,9 @@ class delivery_carrier(osv.osv):
|
||||||
'partner_id': fields.many2one('res.partner', 'Transport Company', required=True, help="The partner that is doing the delivery service."),
|
'partner_id': fields.many2one('res.partner', 'Transport Company', required=True, help="The partner that is doing the delivery service."),
|
||||||
'product_id': fields.many2one('product.product', 'Delivery Product', required=True),
|
'product_id': fields.many2one('product.product', 'Delivery Product', required=True),
|
||||||
'grids_id': fields.one2many('delivery.grid', 'carrier_id', 'Delivery Grids'),
|
'grids_id': fields.one2many('delivery.grid', 'carrier_id', 'Delivery Grids'),
|
||||||
'price' : fields.function(get_price, string='Price'),
|
'available' : fields.function(get_price, string='Available',type='boolean', multi='price',
|
||||||
|
help="Is the carrier method possible with the current order."),
|
||||||
|
'price' : fields.function(get_price, string='Price', multi='price'),
|
||||||
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it."),
|
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it."),
|
||||||
'normal_price': fields.float('Normal Price', help="Keep empty if the pricing depends on the advanced pricing per destination"),
|
'normal_price': fields.float('Normal Price', help="Keep empty if the pricing depends on the advanced pricing per destination"),
|
||||||
'free_if_more_than': fields.boolean('Free If Order Total Amount Is More Than', help="If the order is more expensive than a certain amount, the customer can benefit from a free shipping"),
|
'free_if_more_than': fields.boolean('Free If Order Total Amount Is More Than', help="If the order is more expensive than a certain amount, the customer can benefit from a free shipping"),
|
||||||
|
|
|
@ -61,6 +61,7 @@ class hr_attendance(osv.osv):
|
||||||
('employee_id', '=', obj.employee_id.id),
|
('employee_id', '=', obj.employee_id.id),
|
||||||
('name', '<', obj.name), ('action', '=', 'sign_in')
|
('name', '<', obj.name), ('action', '=', 'sign_in')
|
||||||
], limit=1, order='name DESC')
|
], limit=1, order='name DESC')
|
||||||
|
if last_signin_id:
|
||||||
last_signin = self.browse(cr, uid, last_signin_id, context=context)[0]
|
last_signin = self.browse(cr, uid, last_signin_id, context=context)[0]
|
||||||
|
|
||||||
# Compute time elapsed between sign-in and sign-out
|
# Compute time elapsed between sign-in and sign-out
|
||||||
|
@ -68,6 +69,8 @@ class hr_attendance(osv.osv):
|
||||||
signout_datetime = datetime.strptime(obj.name, '%Y-%m-%d %H:%M:%S')
|
signout_datetime = datetime.strptime(obj.name, '%Y-%m-%d %H:%M:%S')
|
||||||
workedhours_datetime = (signout_datetime - last_signin_datetime)
|
workedhours_datetime = (signout_datetime - last_signin_datetime)
|
||||||
res[obj.id] = ((workedhours_datetime.seconds) / 60) / 60
|
res[obj.id] = ((workedhours_datetime.seconds) / 60) / 60
|
||||||
|
else:
|
||||||
|
res[obj.id] = False
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
|
|
|
@ -368,7 +368,7 @@ class hr_payslip(osv.osv):
|
||||||
#OR if it starts between the given dates
|
#OR if it starts between the given dates
|
||||||
clause_2 = ['&',('date_start', '<=', date_to),('date_start','>=', date_from)]
|
clause_2 = ['&',('date_start', '<=', date_to),('date_start','>=', date_from)]
|
||||||
#OR if it starts before the date_from and finish after the date_end (or never finish)
|
#OR if it starts before the date_from and finish after the date_end (or never finish)
|
||||||
clause_3 = [('date_start','<=', date_from),'|',('date_end', '=', False),('date_end','>=', date_to)]
|
clause_3 = ['&',('date_start','<=', date_from),'|',('date_end', '=', False),('date_end','>=', date_to)]
|
||||||
clause_final = [('employee_id', '=', employee.id),'|','|'] + clause_1 + clause_2 + clause_3
|
clause_final = [('employee_id', '=', employee.id),'|','|'] + clause_1 + clause_2 + clause_3
|
||||||
contract_ids = contract_obj.search(cr, uid, clause_final, context=context)
|
contract_ids = contract_obj.search(cr, uid, clause_final, context=context)
|
||||||
return contract_ids
|
return contract_ids
|
||||||
|
|
|
@ -149,10 +149,11 @@ class mail_notification(osv.Model):
|
||||||
company = "<a style='color:inherit' href='%s'>%s</a>" % (website_url, user.company_id.name)
|
company = "<a style='color:inherit' href='%s'>%s</a>" % (website_url, user.company_id.name)
|
||||||
else:
|
else:
|
||||||
company = user.company_id.name
|
company = user.company_id.name
|
||||||
sent_by = _('Sent from %(company)s using %(openerp)s')
|
sent_by = _('Sent by %(company)s using %(odoo)s.')
|
||||||
|
|
||||||
signature_company = '<small>%s</small>' % (sent_by % {
|
signature_company = '<small>%s</small>' % (sent_by % {
|
||||||
'company': company,
|
'company': company,
|
||||||
'openerp': "<a style='color:inherit' href='https://www.odoo.com/'>Odoo</a>"
|
'odoo': "<a style='color:inherit' href='https://www.odoo.com/'>Odoo</a>"
|
||||||
})
|
})
|
||||||
footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
|
footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
|
||||||
|
|
||||||
|
@ -185,8 +186,9 @@ class mail_notification(osv.Model):
|
||||||
|
|
||||||
# compute email body (signature, company data)
|
# compute email body (signature, company data)
|
||||||
body_html = message.body
|
body_html = message.body
|
||||||
|
# add user signature except for mail groups, where users are usually adding their own signatures already
|
||||||
|
if user_signature and message.model != 'mail.group':
|
||||||
user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None
|
user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None
|
||||||
if user_signature:
|
|
||||||
signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context)
|
signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context)
|
||||||
body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div')
|
body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div')
|
||||||
|
|
||||||
|
|
|
@ -226,8 +226,15 @@ class mail_group(osv.Model):
|
||||||
except Exception:
|
except Exception:
|
||||||
headers = {}
|
headers = {}
|
||||||
headers['Precedence'] = 'list'
|
headers['Precedence'] = 'list'
|
||||||
|
# avoid out-of-office replies from MS Exchange
|
||||||
|
# http://blogs.technet.com/b/exchange/archive/2006/10/06/3395024.aspx
|
||||||
|
headers['X-Auto-Response-Suppress'] = 'OOF'
|
||||||
if group.alias_domain and group.alias_name:
|
if group.alias_domain and group.alias_name:
|
||||||
headers['List-Id'] = '%s.%s' % (group.alias_name, group.alias_domain)
|
headers['List-Id'] = '%s.%s' % (group.alias_name, group.alias_domain)
|
||||||
headers['List-Post'] = '<mailto:%s@%s>' % (group.alias_name, group.alias_domain)
|
headers['List-Post'] = '<mailto:%s@%s>' % (group.alias_name, group.alias_domain)
|
||||||
|
# Avoid users thinking it was a personal message
|
||||||
|
# X-Forge-To: will replace To: after SMTP envelope is determined by ir.mail.server
|
||||||
|
list_to = '"%s" <%s@%s>' % (group.name, group.alias_name, group.alias_domain)
|
||||||
|
headers['X-Forge-To'] = list_to
|
||||||
res['headers'] = '%s' % headers
|
res['headers'] = '%s' % headers
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -467,14 +467,10 @@ class test_mail(TestMail):
|
||||||
'message_post: notification email subject incorrect')
|
'message_post: notification email subject incorrect')
|
||||||
self.assertIn(_body1, sent_email['body'],
|
self.assertIn(_body1, sent_email['body'],
|
||||||
'message_post: notification email body incorrect')
|
'message_post: notification email body incorrect')
|
||||||
self.assertIn(user_raoul.signature, sent_email['body'],
|
|
||||||
'message_post: notification email body should contain the sender signature')
|
|
||||||
self.assertIn('Pigs rules', sent_email['body_alternative'],
|
self.assertIn('Pigs rules', sent_email['body_alternative'],
|
||||||
'message_post: notification email body alternative should contain the body')
|
'message_post: notification email body alternative should contain the body')
|
||||||
self.assertNotIn('<p>', sent_email['body_alternative'],
|
self.assertNotIn('<p>', sent_email['body_alternative'],
|
||||||
'message_post: notification email body alternative still contains html')
|
'message_post: notification email body alternative still contains html')
|
||||||
self.assertIn(html2plaintext(user_raoul.signature), sent_email['body_alternative'],
|
|
||||||
'message_post: notification email body alternative should contain the sender signature')
|
|
||||||
self.assertFalse(sent_email['references'],
|
self.assertFalse(sent_email['references'],
|
||||||
'message_post: references should be False when sending a message that is not a reply')
|
'message_post: references should be False when sending a message that is not a reply')
|
||||||
|
|
||||||
|
@ -538,14 +534,10 @@ class test_mail(TestMail):
|
||||||
'message_post: notification email subject incorrect')
|
'message_post: notification email subject incorrect')
|
||||||
self.assertIn(html_sanitize(_body2), sent_email['body'],
|
self.assertIn(html_sanitize(_body2), sent_email['body'],
|
||||||
'message_post: notification email does not contain the body')
|
'message_post: notification email does not contain the body')
|
||||||
self.assertIn(user_raoul.signature, sent_email['body'],
|
|
||||||
'message_post: notification email body should contain the sender signature')
|
|
||||||
self.assertIn('Pigs rocks', sent_email['body_alternative'],
|
self.assertIn('Pigs rocks', sent_email['body_alternative'],
|
||||||
'message_post: notification email body alternative should contain the body')
|
'message_post: notification email body alternative should contain the body')
|
||||||
self.assertNotIn('<p>', sent_email['body_alternative'],
|
self.assertNotIn('<p>', sent_email['body_alternative'],
|
||||||
'message_post: notification email body alternative still contains html')
|
'message_post: notification email body alternative still contains html')
|
||||||
self.assertIn(html2plaintext(user_raoul.signature), sent_email['body_alternative'],
|
|
||||||
'message_post: notification email body alternative should contain the sender signature')
|
|
||||||
self.assertIn(msg_message_id, sent_email['references'],
|
self.assertIn(msg_message_id, sent_email['references'],
|
||||||
'message_post: notification email references lacks parent message message_id')
|
'message_post: notification email references lacks parent message message_id')
|
||||||
# Test: attachments + download
|
# Test: attachments + download
|
||||||
|
|
|
@ -19,11 +19,15 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
from openerp import tools
|
||||||
|
|
||||||
from openerp.osv import osv
|
from openerp.osv import osv
|
||||||
from openerp.api import Environment
|
from openerp.api import Environment
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class procurement_compute_all(osv.osv_memory):
|
class procurement_compute_all(osv.osv_memory):
|
||||||
_name = 'procurement.order.compute.all'
|
_name = 'procurement.order.compute.all'
|
||||||
_description = 'Compute all schedulers'
|
_description = 'Compute all schedulers'
|
||||||
|
@ -41,6 +45,15 @@ class procurement_compute_all(osv.osv_memory):
|
||||||
#As this function is in a new thread, i need to open a new cursor, because the old one may be closed
|
#As this function is in a new thread, i need to open a new cursor, because the old one may be closed
|
||||||
|
|
||||||
new_cr = self.pool.cursor()
|
new_cr = self.pool.cursor()
|
||||||
|
# Avoid to run the scheduler multiple times in the same time
|
||||||
|
try:
|
||||||
|
with tools.mute_logger('openerp.sql_db'):
|
||||||
|
new_cr.execute("SELECT id FROM ir_cron WHERE id = %s FOR UPDATE NOWAIT", (scheduler_cron_id,))
|
||||||
|
except Exception:
|
||||||
|
_logger.info('Attempt to run procurement scheduler aborted, as already running')
|
||||||
|
new_cr.rollback()
|
||||||
|
new_cr.close()
|
||||||
|
return {}
|
||||||
user = self.pool.get('res.users').browse(new_cr, uid, uid, context=context)
|
user = self.pool.get('res.users').browse(new_cr, uid, uid, context=context)
|
||||||
comps = [x.id for x in user.company_ids]
|
comps = [x.id for x in user.company_ids]
|
||||||
for comp in comps:
|
for comp in comps:
|
||||||
|
|
|
@ -395,6 +395,7 @@ class product_attribute_price(osv.osv):
|
||||||
|
|
||||||
class product_attribute_line(osv.osv):
|
class product_attribute_line(osv.osv):
|
||||||
_name = "product.attribute.line"
|
_name = "product.attribute.line"
|
||||||
|
_rec_name = 'attribute_id'
|
||||||
_columns = {
|
_columns = {
|
||||||
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade'),
|
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade'),
|
||||||
'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='restrict'),
|
'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='restrict'),
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="project_id" domain="[('state', '!=', 'close')]" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
|
<field name="project_id" domain="[('state','not in', ('close', 'cancelled'))]" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
|
||||||
<field name="user_id"
|
<field name="user_id"
|
||||||
options='{"no_open": True}'
|
options='{"no_open": True}'
|
||||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'project.group_project_user']}"/>
|
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'project.group_project_user']}"/>
|
||||||
|
|
|
@ -632,7 +632,7 @@ class sale_order(osv.osv):
|
||||||
compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
|
compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
compose_form_id = False
|
compose_form_id = False
|
||||||
ctx = dict(context)
|
ctx = dict()
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'default_model': 'sale.order',
|
'default_model': 'sale.order',
|
||||||
'default_res_id': ids[0],
|
'default_res_id': ids[0],
|
||||||
|
|
|
@ -37,6 +37,7 @@ class sale_advance_payment_inv(osv.osv_memory):
|
||||||
Use Some Order Lines to invoice a selection of the sales order lines."""),
|
Use Some Order Lines to invoice a selection of the sales order lines."""),
|
||||||
'qtty': fields.float('Quantity', digits=(16, 2), required=True),
|
'qtty': fields.float('Quantity', digits=(16, 2), required=True),
|
||||||
'product_id': fields.many2one('product.product', 'Advance Product',
|
'product_id': fields.many2one('product.product', 'Advance Product',
|
||||||
|
domain=[('type', '=', 'service')],
|
||||||
help="""Select a product of type service which is called 'Advance Product'.
|
help="""Select a product of type service which is called 'Advance Product'.
|
||||||
You may have to create it and set it as a default value on this field."""),
|
You may have to create it and set it as a default value on this field."""),
|
||||||
'amount': fields.float('Advance Amount', digits_compute= dp.get_precision('Account'),
|
'amount': fields.float('Advance Amount', digits_compute= dp.get_precision('Account'),
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<field name="model">product.template</field>
|
<field name="model">product.template</field>
|
||||||
<field name="inherit_id" ref="product.product_template_form_view"/>
|
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<group name="procurement_uom" position="after">
|
<group name="procurement" position="after">
|
||||||
<group string="Project Management Information" attrs="{'invisible': [('type', '!=', 'service')]}">
|
<group string="Project Management Information" attrs="{'invisible': [('type', '!=', 'service')]}">
|
||||||
<field name="auto_create_task"/>
|
<field name="auto_create_task"/>
|
||||||
<field name="project_id" attrs="{'invisible':['|', ('type','!=','service'), ('auto_create_task', '=', False)]}"/>
|
<field name="project_id" attrs="{'invisible':['|', ('type','!=','service'), ('auto_create_task', '=', False)]}"/>
|
||||||
|
|
|
@ -25,6 +25,10 @@ class contactus(http.Controller):
|
||||||
values.update(kwargs=kwargs.items())
|
values.update(kwargs=kwargs.items())
|
||||||
return request.website.render("website.contactus", values)
|
return request.website.render("website.contactus", values)
|
||||||
|
|
||||||
|
def create_lead(self, request, values):
|
||||||
|
""" Allow to be overrided """
|
||||||
|
return request.registry['crm.lead'].create(request.cr, SUPERUSER_ID, values, request.context)
|
||||||
|
|
||||||
@http.route(['/crm/contactus'], type='http', auth="public", website=True)
|
@http.route(['/crm/contactus'], type='http', auth="public", website=True)
|
||||||
def contactus(self, **kwargs):
|
def contactus(self, **kwargs):
|
||||||
def dict_to_str(title, dictvar):
|
def dict_to_str(title, dictvar):
|
||||||
|
@ -41,12 +45,10 @@ class contactus(http.Controller):
|
||||||
post_description = [] # Info to add after the message
|
post_description = [] # Info to add after the message
|
||||||
values = {}
|
values = {}
|
||||||
|
|
||||||
lead_model = request.registry['crm.lead']
|
|
||||||
|
|
||||||
for field_name, field_value in kwargs.items():
|
for field_name, field_value in kwargs.items():
|
||||||
if hasattr(field_value, 'filename'):
|
if hasattr(field_value, 'filename'):
|
||||||
post_file.append(field_value)
|
post_file.append(field_value)
|
||||||
elif field_name in lead_model._all_columns and field_name not in _BLACKLIST:
|
elif field_name in request.registry['crm.lead']._all_columns and field_name not in _BLACKLIST:
|
||||||
values[field_name] = field_value
|
values[field_name] = field_value
|
||||||
elif field_name not in _TECHNICAL: # allow to add some free fields or blacklisted field like ID
|
elif field_name not in _TECHNICAL: # allow to add some free fields or blacklisted field like ID
|
||||||
post_description.append("%s: %s" % (field_name, field_value))
|
post_description.append("%s: %s" % (field_name, field_value))
|
||||||
|
@ -80,7 +82,7 @@ class contactus(http.Controller):
|
||||||
post_description.append("%s: %s" % ("REFERER", environ.get("HTTP_REFERER")))
|
post_description.append("%s: %s" % ("REFERER", environ.get("HTTP_REFERER")))
|
||||||
values['description'] += dict_to_str(_("Environ Fields: "), post_description)
|
values['description'] += dict_to_str(_("Environ Fields: "), post_description)
|
||||||
|
|
||||||
lead_id = lead_model.create(request.cr, SUPERUSER_ID, dict(values, user_id=False), request.context)
|
lead_id = self.create_lead(request, dict(values, user_id=False))
|
||||||
if lead_id:
|
if lead_id:
|
||||||
for field_value in post_file:
|
for field_value in post_file:
|
||||||
attachment_value = {
|
attachment_value = {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class WebsiteForum(http.Controller):
|
||||||
forum_id = request.registry['forum.forum'].create(request.cr, request.uid, {
|
forum_id = request.registry['forum.forum'].create(request.cr, request.uid, {
|
||||||
'name': forum_name,
|
'name': forum_name,
|
||||||
}, context=request.context)
|
}, context=request.context)
|
||||||
return request.redirect("/forum/%s" % slug(forum_id))
|
return request.redirect("/forum/%s" % forum_id)
|
||||||
|
|
||||||
@http.route('/forum/notification_read', type='json', auth="user", methods=['POST'], website=True)
|
@http.route('/forum/notification_read', type='json', auth="user", methods=['POST'], website=True)
|
||||||
def notification_read(self, **kwargs):
|
def notification_read(self, **kwargs):
|
||||||
|
@ -529,7 +529,7 @@ class WebsiteForum(http.Controller):
|
||||||
'website': kwargs.get('website'),
|
'website': kwargs.get('website'),
|
||||||
'email': kwargs.get('email'),
|
'email': kwargs.get('email'),
|
||||||
'city': kwargs.get('city'),
|
'city': kwargs.get('city'),
|
||||||
'country_id': int(kwargs.get('country')),
|
'country_id': int(kwargs.get('country')) if kwargs.get('country') else False,
|
||||||
'website_description': kwargs.get('description'),
|
'website_description': kwargs.get('description'),
|
||||||
}, context=request.context)
|
}, context=request.context)
|
||||||
return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), user.id))
|
return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), user.id))
|
||||||
|
|
|
@ -400,8 +400,9 @@ class Post(osv.Model):
|
||||||
raise KarmaError('Not enough karma to downvote.')
|
raise KarmaError('Not enough karma to downvote.')
|
||||||
|
|
||||||
Vote = self.pool['forum.post.vote']
|
Vote = self.pool['forum.post.vote']
|
||||||
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], limit=1, context=context)
|
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
|
||||||
new_vote = 0
|
new_vote = '1' if upvote else '-1'
|
||||||
|
voted_forum_ids = set()
|
||||||
if vote_ids:
|
if vote_ids:
|
||||||
for vote in Vote.browse(cr, uid, vote_ids, context=context):
|
for vote in Vote.browse(cr, uid, vote_ids, context=context):
|
||||||
if upvote:
|
if upvote:
|
||||||
|
@ -409,9 +410,9 @@ class Post(osv.Model):
|
||||||
else:
|
else:
|
||||||
new_vote = '0' if vote.vote == '1' else '-1'
|
new_vote = '0' if vote.vote == '1' else '-1'
|
||||||
Vote.write(cr, uid, vote_ids, {'vote': new_vote}, context=context)
|
Vote.write(cr, uid, vote_ids, {'vote': new_vote}, context=context)
|
||||||
else:
|
voted_forum_ids.add(vote.post_id.id)
|
||||||
|
for post_id in set(ids) - voted_forum_ids:
|
||||||
for post_id in ids:
|
for post_id in ids:
|
||||||
new_vote = '1' if upvote else '-1'
|
|
||||||
Vote.create(cr, uid, {'post_id': post_id, 'vote': new_vote}, context=context)
|
Vote.create(cr, uid, {'post_id': post_id, 'vote': new_vote}, context=context)
|
||||||
return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]], 'user_vote': new_vote}
|
return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]], 'user_vote': new_vote}
|
||||||
|
|
||||||
|
|
|
@ -40,17 +40,21 @@
|
||||||
}
|
}
|
||||||
this.$target.removeClass('has-error');
|
this.$target.removeClass('has-error');
|
||||||
|
|
||||||
|
var email = $email.length ? $email.val() : false;
|
||||||
|
if (email) {
|
||||||
openerp.jsonRpc('/website_mail/follow', 'call', {
|
openerp.jsonRpc('/website_mail/follow', 'call', {
|
||||||
'id': +this.$target.data('id'),
|
'id': +this.$target.data('id'),
|
||||||
'object': this.$target.data('object'),
|
'object': this.$target.data('object'),
|
||||||
'message_is_follower': this.$target.attr("data-follow") || "off",
|
'message_is_follower': this.$target.attr("data-follow") || "off",
|
||||||
'email': $email.length ? $email.val() : false,
|
'email': email,
|
||||||
}).then(function (follow) {
|
}).then(function (follow) {
|
||||||
self.toggle_subscription(follow, self.email);
|
self.toggle_subscription(follow, email);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toggle_subscription: function(follow, email) {
|
toggle_subscription: function(follow, email) {
|
||||||
console.log(follow, email);
|
console.log(follow, email);
|
||||||
|
follow = follow || (!email && this.$target.attr('data-unsubscribe'));
|
||||||
if (follow) {
|
if (follow) {
|
||||||
this.$target.find(".js_follow_btn").addClass("hidden");
|
this.$target.find(".js_follow_btn").addClass("hidden");
|
||||||
this.$target.find(".js_unfollow_btn").removeClass("hidden");
|
this.$target.find(".js_unfollow_btn").removeClass("hidden");
|
||||||
|
@ -60,8 +64,8 @@
|
||||||
this.$target.find(".js_unfollow_btn").addClass("hidden");
|
this.$target.find(".js_unfollow_btn").addClass("hidden");
|
||||||
}
|
}
|
||||||
this.$target.find('input.js_follow_email')
|
this.$target.find('input.js_follow_email')
|
||||||
.val(email ? email : "")
|
.val(email || "")
|
||||||
.attr("disabled", follow || (email.length && this.is_user) ? "disabled" : false);
|
.attr("disabled", email && (follow || this.is_user) ? "disabled" : false);
|
||||||
this.$target.attr("data-follow", follow ? 'on' : 'off');
|
this.$target.attr("data-follow", follow ? 'on' : 'off');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
<template id="follow">
|
<template id="follow">
|
||||||
<div class="input-group js_follow" t-att-data-id="object.id"
|
<div class="input-group js_follow" t-att-data-id="object.id"
|
||||||
t-att-data-object="object._name"
|
t-att-data-object="object._name"
|
||||||
t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'">
|
t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'"
|
||||||
|
t-att-data-unsubscribe="'unsubscribe' if 'unsubscribe' in request.params else None">
|
||||||
<input
|
<input
|
||||||
type="email" name="email"
|
type="email" name="email"
|
||||||
class="js_follow_email form-control"
|
class="js_follow_email form-control"
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from openerp.osv import osv
|
from openerp.osv import osv
|
||||||
|
from openerp import tools
|
||||||
|
from openerp.tools.translate import _
|
||||||
from openerp.tools.safe_eval import safe_eval as eval
|
from openerp.tools.safe_eval import safe_eval as eval
|
||||||
|
from openerp.addons.website.models.website import slug
|
||||||
|
|
||||||
class MailGroup(osv.Model):
|
class MailGroup(osv.Model):
|
||||||
_inherit = 'mail.group'
|
_inherit = 'mail.group'
|
||||||
|
@ -16,9 +18,41 @@ class MailGroup(osv.Model):
|
||||||
except Exception:
|
except Exception:
|
||||||
headers = {}
|
headers = {}
|
||||||
headers.update({
|
headers.update({
|
||||||
'List-Archive': '<%s/groups/%s>' % (base_url, group.id),
|
'List-Archive': '<%s/groups/%s>' % (base_url, slug(group)),
|
||||||
'List-Subscribe': '<%s/groups>' % (base_url),
|
'List-Subscribe': '<%s/groups>' % (base_url),
|
||||||
'List-Unsubscribe': '<%s/groups>' % (base_url),
|
'List-Unsubscribe': '<%s/groups?unsubscribe>' % (base_url,),
|
||||||
})
|
})
|
||||||
res['headers'] = '%s' % headers
|
res['headers'] = '%s' % headers
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class MailMail(osv.Model):
|
||||||
|
_inherit = 'mail.mail'
|
||||||
|
|
||||||
|
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
|
||||||
|
""" Short-circuit parent method for mail groups, replace the default
|
||||||
|
footer with one appropriate for mailing-lists."""
|
||||||
|
|
||||||
|
if mail.model == 'mail.group' and mail.res_id:
|
||||||
|
# no super() call on purpose, no private links that could be quoted!
|
||||||
|
group = self.pool['mail.group'].browse(cr, uid, mail.res_id, context=context)
|
||||||
|
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||||
|
vals = {
|
||||||
|
'maillist': _('Mailing-List'),
|
||||||
|
'post_to': _('Post to'),
|
||||||
|
'unsub': _('Unsubscribe'),
|
||||||
|
'mailto': 'mailto:%s@%s' % (group.alias_name, group.alias_domain),
|
||||||
|
'group_url': '%s/groups/%s' % (base_url, slug(group)),
|
||||||
|
'unsub_url': '%s/groups?unsubscribe' % (base_url,),
|
||||||
|
}
|
||||||
|
footer = """_______________________________________________
|
||||||
|
%(maillist)s: %(group_url)s
|
||||||
|
%(post_to)s: %(mailto)s
|
||||||
|
%(unsub)s: %(unsub_url)s
|
||||||
|
""" % vals
|
||||||
|
body = tools.append_content_to_html(mail.body, footer, container_tag='div')
|
||||||
|
return body
|
||||||
|
else:
|
||||||
|
return super(MailMail, self).send_get_mail_body(cr, uid, mail,
|
||||||
|
partner=partner,
|
||||||
|
context=context)
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="container mt32">
|
<div class="container mt32">
|
||||||
|
<div t-if="'unsubscribe' in request.params" class="col-md-offset-9 col-md-3 alert alert-info">
|
||||||
|
<h3>Need to unsubscribe? It's right here! <span class="fa fa-2x fa-arrow-down pull-right"></span></h3>
|
||||||
|
</div>
|
||||||
<div class="row mt8" t-foreach="groups" t-as="group">
|
<div class="row mt8" t-foreach="groups" t-as="group">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<img t-att-src="'/website/image?model=mail.group&field=image_small&id='+str(group['id'])" class="pull-left"/>
|
<img t-att-src="'/website/image?model=mail.group&field=image_small&id='+str(group['id'])" class="pull-left"/>
|
||||||
|
|
|
@ -660,7 +660,7 @@ class website_sale(http.Controller):
|
||||||
if not order:
|
if not order:
|
||||||
return {
|
return {
|
||||||
'state': 'error',
|
'state': 'error',
|
||||||
'message': '<p>There seems to be an error with your request.</p>',
|
'message': '<p>%s</p>' % _('There seems to be an error with your request.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_ids = request.registry['payment.transaction'].search(
|
tx_ids = request.registry['payment.transaction'].search(
|
||||||
|
@ -672,7 +672,7 @@ class website_sale(http.Controller):
|
||||||
if order.amount_total:
|
if order.amount_total:
|
||||||
return {
|
return {
|
||||||
'state': 'error',
|
'state': 'error',
|
||||||
'message': '<p>There seems to be an error with your request.</p>',
|
'message': '<p>%s</p>' % _('There seems to be an error with your request.'),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
state = 'done'
|
state = 'done'
|
||||||
|
@ -682,15 +682,15 @@ class website_sale(http.Controller):
|
||||||
tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
|
tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
|
||||||
state = tx.state
|
state = tx.state
|
||||||
if state == 'done':
|
if state == 'done':
|
||||||
message = '<p>Your payment has been received.</p>'
|
message = '<p>%s</p>' % _('Your payment has been received.')
|
||||||
elif state == 'cancel':
|
elif state == 'cancel':
|
||||||
message = '<p>The payment seems to have been canceled.</p>'
|
message = '<p>%s</p>' % _('The payment seems to have been canceled.')
|
||||||
elif state == 'pending' and tx.acquirer_id.validation == 'manual':
|
elif state == 'pending' and tx.acquirer_id.validation == 'manual':
|
||||||
message = '<p>Your transaction is waiting confirmation.</p>'
|
message = '<p>%s</p>' % _('Your transaction is waiting confirmation.')
|
||||||
if tx.acquirer_id.post_msg:
|
if tx.acquirer_id.post_msg:
|
||||||
message += tx.acquirer_id.post_msg
|
message += tx.acquirer_id.post_msg
|
||||||
else:
|
else:
|
||||||
message = '<p>Your transaction is waiting confirmation.</p>'
|
message = '<p>%s</p>' % _('Your transaction is waiting confirmation.')
|
||||||
validation = tx.acquirer_id.validation
|
validation = tx.acquirer_id.validation
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -288,7 +288,7 @@
|
||||||
<select class="form-control" name="attrib">
|
<select class="form-control" name="attrib">
|
||||||
<option value=""/>
|
<option value=""/>
|
||||||
<t t-foreach="a.value_ids" t-as="v">
|
<t t-foreach="a.value_ids" t-as="v">
|
||||||
<option t-att-value="'%s-%s' % (a.id,v.id)" t-field="v.name" t-att-selected="'selected' if v.id in attrib_set else ''"/>
|
<option t-att-value="'%s-%s' % (a.id,v.id)" t-esc="v.name" t-att-selected="'selected' if v.id in attrib_set else ''"/>
|
||||||
</t>
|
</t>
|
||||||
</select>
|
</select>
|
||||||
</t>
|
</t>
|
||||||
|
@ -916,14 +916,14 @@
|
||||||
|
|
||||||
<div class="clearfix"/>
|
<div class="clearfix"/>
|
||||||
|
|
||||||
<div class="form-group col-lg-6" groups="sale.group_delivery_invoice_address">
|
<div class="form-group col-lg-6">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="shipping_different" t-att-checked="checkout.get('shipping_different')"/>
|
<input type="checkbox" name="shipping_different" t-att-checked="checkout.get('shipping_different')"/>
|
||||||
<span>Ship to a different address</span>
|
<span>Ship to a different address</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="js_shipping row mb16" t-att-style="not checkout.get('shipping_different') and 'display:none' or ''" groups="sale.group_delivery_invoice_address">
|
<div class="js_shipping row mb16" t-att-style="not checkout.get('shipping_different') and 'display:none' or ''">
|
||||||
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
|
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
|
||||||
|
|
||||||
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
|
||||||
|
@ -1061,7 +1061,7 @@
|
||||||
<div>
|
<div>
|
||||||
<a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a>
|
<a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a>
|
||||||
</div>
|
</div>
|
||||||
<t groups="sale.group_delivery_invoice_address">
|
<t>
|
||||||
<h4 class="mt32">Ship To:</h4>
|
<h4 class="mt32">Ship To:</h4>
|
||||||
<t t-if="website_sale_order.partner_shipping_id and website_sale_order.partner_shipping_id.id != website_sale_order.partner_invoice_id.id">
|
<t t-if="website_sale_order.partner_shipping_id and website_sale_order.partner_shipping_id.id != website_sale_order.partner_invoice_id.id">
|
||||||
<div t-field="order.partner_shipping_id" t-field-options='{
|
<div t-field="order.partner_shipping_id" t-field-options='{
|
||||||
|
@ -1146,7 +1146,7 @@
|
||||||
"widget": "contact",
|
"widget": "contact",
|
||||||
"fields": ["address", "name", "phone", "email"]
|
"fields": ["address", "name", "phone", "email"]
|
||||||
}'/>
|
}'/>
|
||||||
<t groups="sale.group_delivery_invoice_address">
|
<t>
|
||||||
<h4 class="mt32">Ship To:</h4>
|
<h4 class="mt32">Ship To:</h4>
|
||||||
<t t-if="order.partner_shipping_id and order.partner_shipping_id.id != order.partner_invoice_id.id">
|
<t t-if="order.partner_shipping_id and order.partner_shipping_id.id != order.partner_invoice_id.id">
|
||||||
<div t-field="order.partner_shipping_id" t-field-options='{
|
<div t-field="order.partner_shipping_id" t-field-options='{
|
||||||
|
|
|
@ -31,13 +31,16 @@
|
||||||
<li t-foreach="deliveries" t-as="delivery">
|
<li t-foreach="deliveries" t-as="delivery">
|
||||||
<label>
|
<label>
|
||||||
<input t-att-value="delivery.id" type="radio" name="delivery_type"
|
<input t-att-value="delivery.id" type="radio" name="delivery_type"
|
||||||
t-att-checked="order.carrier_id and order.carrier_id.id == delivery.id and 'checked' or False"/>
|
t-att-checked="order.carrier_id and order.carrier_id.id == delivery.id and 'checked' or False"
|
||||||
|
t-att-disabled="delivery.available and '0' or '1'"/>
|
||||||
<span t-field="delivery.name"/>
|
<span t-field="delivery.name"/>
|
||||||
|
<t t-if="delivery.available">
|
||||||
<span class="badge" t-field="delivery.price"
|
<span class="badge" t-field="delivery.price"
|
||||||
t-field-options='{
|
t-field-options='{
|
||||||
"widget": "monetary",
|
"widget": "monetary",
|
||||||
"display_currency": "website.pricelist_id.currency_id"
|
"display_currency": "website.pricelist_id.currency_id"
|
||||||
}'/>
|
}'/>
|
||||||
|
</t>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -415,6 +415,13 @@ class ir_mail_server(osv.osv):
|
||||||
smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc])))
|
smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc])))
|
||||||
assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)"
|
assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)"
|
||||||
|
|
||||||
|
x_forge_to = message['X-Forge-To']
|
||||||
|
if x_forge_to:
|
||||||
|
# `To:` header forged, e.g. for posting on mail.groups, to avoid confusion
|
||||||
|
del message['X-Forge-To']
|
||||||
|
del message['To'] # avoid multiple To: headers!
|
||||||
|
message['To'] = x_forge_to
|
||||||
|
|
||||||
# Do not actually send emails in testing mode!
|
# Do not actually send emails in testing mode!
|
||||||
if getattr(threading.currentThread(), 'testing', False):
|
if getattr(threading.currentThread(), 'testing', False):
|
||||||
_test_logger.info("skip sending email in test mode")
|
_test_logger.info("skip sending email in test mode")
|
||||||
|
|
|
@ -319,10 +319,10 @@ class ir_values(osv.osv):
|
||||||
(SELECT company_id from res_users where id = %%s)
|
(SELECT company_id from res_users where id = %%s)
|
||||||
)
|
)
|
||||||
%s
|
%s
|
||||||
ORDER BY v.user_id, u.company_id"""
|
ORDER BY v.user_id, u.company_id, v.key2"""
|
||||||
params = ('default', model, uid, uid)
|
params = ('default', model, uid, uid)
|
||||||
if condition:
|
if condition:
|
||||||
query %= 'AND v.key2 = %s'
|
query %= 'AND (v.key2 = %s OR v.key2 IS NULL)'
|
||||||
params += (condition[:200],)
|
params += (condition[:200],)
|
||||||
else:
|
else:
|
||||||
query %= 'AND v.key2 is NULL'
|
query %= 'AND v.key2 is NULL'
|
||||||
|
|
Loading…
Reference in New Issue