[MERGE] forward port of branch saas-4 up to 7ecaab9

This commit is contained in:
Denis Ledoux 2014-08-12 16:27:57 +02:00
commit fc74431c1a
13 changed files with 122 additions and 84 deletions

View File

@ -52,7 +52,7 @@ class meeting_invitation(http.Controller):
# Function used, in RPC to check every 5 minutes, if notification to do for an event or not # Function used, in RPC to check every 5 minutes, if notification to do for an event or not
@http.route('/calendar/notify', type='json', auth="none") @http.route('/calendar/notify', type='json', auth="none")
def notify(self): def notify(self):
registry = openerp.modules.registry.RegistryManager.get(request.session.db) registry = request.registry
uid = request.session.uid uid = request.session.uid
context = request.session.context context = request.session.context
with registry.cursor() as cr: with registry.cursor() as cr:
@ -61,7 +61,7 @@ class meeting_invitation(http.Controller):
@http.route('/calendar/notify_ack', type='json', auth="none") @http.route('/calendar/notify_ack', type='json', auth="none")
def notify_ack(self, type=''): def notify_ack(self, type=''):
registry = openerp.modules.registry.RegistryManager.get(request.session.db) registry = request.registry
uid = request.session.uid uid = request.session.uid
context = request.session.context context = request.session.context
with registry.cursor() as cr: with registry.cursor() as cr:

View File

@ -49,7 +49,7 @@ class account_coda_import(osv.osv_memory):
return tmp_account_id return tmp_account_id
_defaults = { _defaults = {
'coda_fname': lambda *a: '', 'coda_fname': 'coda.txt',
'temporary_account_id': _get_default_tmp_account, 'temporary_account_id': _get_default_tmp_account,
} }

View File

@ -22,6 +22,7 @@
import base64 import base64
import logging import logging
import re import re
from email.utils import formataddr
from urllib import urlencode from urllib import urlencode
from urlparse import urljoin from urlparse import urljoin
@ -184,10 +185,9 @@ class mail_mail(osv.Model):
- elif 'partner', no notificatoin or no doc: recipient specific (Partner Name <email>) - elif 'partner', no notificatoin or no doc: recipient specific (Partner Name <email>)
- else fallback on mail.email_to splitting """ - else fallback on mail.email_to splitting """
if partner and mail.notification and mail.record_name: if partner and mail.notification and mail.record_name:
sanitized_record_name = re.sub(r'[^\w+.]+', '-', mail.record_name) email_to = [formataddr((_('Followers of %s') % mail.record_name, partner.email))]
email_to = [_('"Followers of %s" <%s>') % (sanitized_record_name, partner.email)]
elif partner: elif partner:
email_to = ['%s <%s>' % (partner.name, partner.email)] email_to = [formataddr((partner.name, partner.email))]
else: else:
email_to = tools.email_split(mail.email_to) email_to = tools.email_split(mail.email_to)
return email_to return email_to

View File

@ -25,6 +25,7 @@ import re
from openerp import tools from openerp import tools
from email.header import decode_header from email.header import decode_header
from email.utils import formataddr
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.osv import osv, orm, fields from openerp.osv import osv, orm, fields
from openerp.tools import html_email_clean from openerp.tools import html_email_clean
@ -175,9 +176,9 @@ class mail_message(osv.Model):
def _get_default_from(self, cr, uid, context=None): def _get_default_from(self, cr, uid, context=None):
this = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) this = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
if this.alias_name and this.alias_domain: if this.alias_name and this.alias_domain:
return '%s <%s@%s>' % (this.name, this.alias_name, this.alias_domain) return formataddr((this.name, '%s@%s' % (this.alias_name, this.alias_domain)))
elif this.email: elif this.email:
return '%s <%s>' % (this.name, this.email) return formataddr((this.name, this.email))
raise osv.except_osv(_('Invalid Action!'), _("Unable to send email, please configure the sender's email address or alias.")) raise osv.except_osv(_('Invalid Action!'), _("Unable to send email, please configure the sender's email address or alias."))
def _get_default_author(self, cr, uid, context=None): def _get_default_author(self, cr, uid, context=None):
@ -794,10 +795,8 @@ class mail_message(osv.Model):
email_reply_to = emails[0] email_reply_to = emails[0]
document_name = self.pool[model].name_get(cr, SUPERUSER_ID, [res_id], context=context)[0] document_name = self.pool[model].name_get(cr, SUPERUSER_ID, [res_id], context=context)[0]
if document_name: if document_name:
# sanitize document name
sanitized_doc_name = re.sub(r'[^\w+.]+', '-', document_name[1])
# generate reply to # generate reply to
email_reply_to = _('"Followers of %s" <%s>') % (sanitized_doc_name, email_reply_to) email_reply_to = formataddr((_('Followers of %s') % document_name[1], email_reply_to))
return email_reply_to return email_reply_to

View File

@ -450,7 +450,7 @@ class test_mail(TestMail):
# Test: notifications emails: to a and b, c is email only, r is author # Test: notifications emails: to a and b, c is email only, r is author
# test_emailto = ['Administrator <a@a>', 'Bert Tartopoils <b@b>'] # test_emailto = ['Administrator <a@a>', 'Bert Tartopoils <b@b>']
test_emailto = ['"Followers of -Pigs-" <a@a>', '"Followers of -Pigs-" <b@b>'] test_emailto = [u'"Followers of \\"Pigs\\" !\xf9 $%-" <a@a>', u'"Followers of \\"Pigs\\" !\xf9 $%-" <b@b>']
self.assertEqual(len(sent_emails), 2, self.assertEqual(len(sent_emails), 2,
'message_post: notification emails wrong number of send emails') 'message_post: notification emails wrong number of send emails')
self.assertEqual(set([m['email_to'][0] for m in sent_emails]), set(test_emailto), self.assertEqual(set([m['email_to'][0] for m in sent_emails]), set(test_emailto),
@ -462,7 +462,7 @@ class test_mail(TestMail):
'message_post: notification email sent to more than one email address instead of a precise partner') 'message_post: notification email sent to more than one email address instead of a precise partner')
self.assertIn(sent_email['email_to'][0], test_emailto, self.assertIn(sent_email['email_to'][0], test_emailto,
'message_post: notification email email_to incorrect') 'message_post: notification email email_to incorrect')
self.assertEqual(sent_email['reply_to'], '"Followers of -Pigs-" <group+pigs@schlouby.fr>', self.assertEqual(sent_email['reply_to'], u'"Followers of \\"Pigs\\" !\xf9 $%-" <group+pigs@schlouby.fr>',
'message_post: notification email reply_to incorrect') 'message_post: notification email reply_to incorrect')
self.assertEqual(_subject, sent_email['subject'], self.assertEqual(_subject, sent_email['subject'],
'message_post: notification email subject incorrect') 'message_post: notification email subject incorrect')
@ -520,7 +520,7 @@ class test_mail(TestMail):
# Test: emails send by server (to a, b, c, d) # Test: emails send by server (to a, b, c, d)
# test_emailto = [u'Administrator <a@a>', u'Bert Tartopoils <b@b>', u'Carine Poilvache <c@c>', u'D\xe9d\xe9 Grosbedon <d@d>'] # test_emailto = [u'Administrator <a@a>', u'Bert Tartopoils <b@b>', u'Carine Poilvache <c@c>', u'D\xe9d\xe9 Grosbedon <d@d>']
test_emailto = [u'"Followers of Pigs" <a@a>', u'"Followers of Pigs" <b@b>', u'"Followers of Pigs" <c@c>', u'"Followers of Pigs" <d@d>'] test_emailto = [u'Followers of Pigs <a@a>', u'Followers of Pigs <b@b>', u'Followers of Pigs <c@c>', u'Followers of Pigs <d@d>']
# self.assertEqual(len(sent_emails), 3, 'sent_email number of sent emails incorrect') # self.assertEqual(len(sent_emails), 3, 'sent_email number of sent emails incorrect')
for sent_email in sent_emails: for sent_email in sent_emails:
self.assertEqual(sent_email['email_from'], 'Raoul Grosbedon <r@r>', self.assertEqual(sent_email['email_from'], 'Raoul Grosbedon <r@r>',

View File

@ -81,8 +81,8 @@ class TestMailMessage(TestMail):
alias_domain = 'schlouby.fr' alias_domain = 'schlouby.fr'
raoul_from = 'Raoul Grosbedon <raoul@raoul.fr>' raoul_from = 'Raoul Grosbedon <raoul@raoul.fr>'
raoul_from_alias = 'Raoul Grosbedon <raoul@schlouby.fr>' raoul_from_alias = 'Raoul Grosbedon <raoul@schlouby.fr>'
raoul_reply = '"Followers of Pigs" <raoul@raoul.fr>' raoul_reply = 'Followers of Pigs <raoul@raoul.fr>'
raoul_reply_alias = '"Followers of Pigs" <group+pigs@schlouby.fr>' raoul_reply_alias = 'Followers of Pigs <group+pigs@schlouby.fr>'
# -------------------------------------------------- # --------------------------------------------------
# Case1: without alias_domain # Case1: without alias_domain

View File

@ -42,8 +42,8 @@ class AcquirerPaypal(osv.Model):
_columns = { _columns = {
'paypal_email_account': fields.char('Paypal Email ID', required_if_provider='paypal'), 'paypal_email_account': fields.char('Paypal Email ID', required_if_provider='paypal'),
'paypal_seller_account': fields.char( 'paypal_seller_account': fields.char(
'Paypal Seller ID', 'Paypal Merchant ID',
help='The Seller ID is used to ensure communications coming from Paypal are valid and secured.'), help='The Merchant ID is used to ensure communications coming from Paypal are valid and secured.'),
'paypal_use_ipn': fields.boolean('Use IPN', help='Paypal Instant Payment Notification'), 'paypal_use_ipn': fields.boolean('Use IPN', help='Paypal Instant Payment Notification'),
# Server 2 server # Server 2 server
'paypal_api_enabled': fields.boolean('Use Rest API'), 'paypal_api_enabled': fields.boolean('Use Rest API'),

View File

@ -28,6 +28,7 @@ from openerp.osv import fields
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp import tools from openerp import tools
from psycopg2 import OperationalError
class procurement_order(osv.osv): class procurement_order(osv.osv):
_inherit = 'procurement.order' _inherit = 'procurement.order'
@ -70,33 +71,45 @@ class procurement_order(osv.osv):
cr.commit() cr.commit()
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
maxdate = (datetime.today() + relativedelta(days=company.schedule_range)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) maxdate = (datetime.today() + relativedelta(days=company.schedule_range)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
offset = 0 prev_ids = []
while True: while True:
ids = procurement_obj.search(cr, uid, [('state', '=', 'confirmed'), ('procure_method', '=', 'make_to_order')], offset=offset, limit=500, order='priority, date_planned', context=context) ids = procurement_obj.search(cr, uid, [('state', '=', 'confirmed'), ('procure_method', '=', 'make_to_order'), ('date_planned', '<', maxdate)], limit=500, order='priority, date_planned', context=context)
for proc in procurement_obj.browse(cr, uid, ids, context=context): for proc in procurement_obj.browse(cr, uid, ids, context=context):
if maxdate >= proc.date_planned: try:
self.signal_button_check(cr, uid, [proc.id]) self.signal_button_check(cr, uid, [proc.id])
else:
offset += 1
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
if not ids: except OperationalError:
if use_new_cursor:
cr.rollback()
continue
else:
raise
if not ids or prev_ids == ids:
break break
offset = 0 else:
prev_ids = ids
ids = [] ids = []
prev_ids = []
while True: while True:
report_ids = [] ids = procurement_obj.search(cr, uid, [('state', '=', 'confirmed'), ('procure_method', '=', 'make_to_stock'), ('date_planned', '<', maxdate)], limit=500)
ids = procurement_obj.search(cr, uid, [('state', '=', 'confirmed'), ('procure_method', '=', 'make_to_stock')], offset=offset)
for proc in procurement_obj.browse(cr, uid, ids): for proc in procurement_obj.browse(cr, uid, ids):
if maxdate >= proc.date_planned: try:
self.signal_button_check(cr, uid, [proc.id]) self.signal_button_check(cr, uid, [proc.id])
report_ids.append(proc.id)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
offset += len(ids) except OperationalError:
if not ids: break if use_new_cursor:
cr.rollback()
continue
else:
raise
if not ids or prev_ids == ids:
break
else:
prev_ids = ids
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
@ -203,52 +216,66 @@ class procurement_order(osv.osv):
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint') orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
procurement_obj = self.pool.get('procurement.order') procurement_obj = self.pool.get('procurement.order')
offset = 0
ids = [1] ids = [1]
prev_ids = []
if automatic: if automatic:
self.create_automatic_op(cr, uid, context=context) self.create_automatic_op(cr, uid, context=context)
while ids: orderpoint_ids = orderpoint_obj.search(cr, uid, [])
ids = orderpoint_obj.search(cr, uid, [], offset=offset, limit=100) while orderpoint_ids:
ids = orderpoint_ids[:100]
del orderpoint_ids[:100]
for op in orderpoint_obj.browse(cr, uid, ids, context=context): for op in orderpoint_obj.browse(cr, uid, ids, context=context):
prods = self._product_virtual_get(cr, uid, op) try:
if prods is None: prods = self._product_virtual_get(cr, uid, op)
continue if prods is None:
if prods < op.product_min_qty:
qty = max(op.product_min_qty, op.product_max_qty)-prods
reste = qty % op.qty_multiple
if reste > 0:
qty += op.qty_multiple - reste
if qty <= 0:
continue continue
if op.product_id.type not in ('consu'): if prods < op.product_min_qty:
if op.procurement_draft_ids: qty = max(op.product_min_qty, op.product_max_qty)-prods
# Check draft procurement related to this order point
pro_ids = [x.id for x in op.procurement_draft_ids] reste = qty % op.qty_multiple
procure_datas = procurement_obj.read( if reste > 0:
cr, uid, pro_ids, ['id', 'product_qty'], context=context) qty += op.qty_multiple - reste
to_generate = qty
for proc_data in procure_datas: if qty <= 0:
if to_generate >= proc_data['product_qty']: continue
self.signal_button_confirm(cr, uid, [proc_data['id']]) if op.product_id.type not in ('consu'):
procurement_obj.write(cr, uid, [proc_data['id']], {'origin': op.name}, context=context) if op.procurement_draft_ids:
to_generate -= proc_data['product_qty'] # Check draft procurement related to this order point
if not to_generate: pro_ids = [x.id for x in op.procurement_draft_ids]
break procure_datas = procurement_obj.read(
qty = to_generate cr, uid, pro_ids, ['id', 'product_qty'], context=context)
to_generate = qty
for proc_data in procure_datas:
if to_generate >= proc_data['product_qty']:
self.signal_button_confirm(cr, uid, [proc_data['id']])
procurement_obj.write(cr, uid, [proc_data['id']], {'origin': op.name}, context=context)
to_generate -= proc_data['product_qty']
if not to_generate:
break
qty = to_generate
if qty:
proc_id = procurement_obj.create(cr, uid,
self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context),
context=context)
self.signal_button_confirm(cr, uid, [proc_id])
self.signal_button_check(cr, uid, [proc_id])
orderpoint_obj.write(cr, uid, [op.id],
{'procurement_id': proc_id}, context=context)
if use_new_cursor:
cr.commit()
except OperationalError:
if use_new_cursor:
orderpoint_ids.append(op.id)
cr.rollback()
continue
else:
raise
if prev_ids == ids:
break
else:
prev_ids = ids
if qty:
proc_id = procurement_obj.create(cr, uid,
self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context),
context=context)
self.signal_button_confirm(cr, uid, [proc_id])
self.signal_button_check(cr, uid, [proc_id])
orderpoint_obj.write(cr, uid, [op.id],
{'procurement_id': proc_id}, context=context)
offset += len(ids)
if use_new_cursor:
cr.commit()
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
cr.close() cr.close()

View File

@ -117,8 +117,8 @@
<xpath expr="//ul[@id='reseller_countries']" position="after"> <xpath expr="//ul[@id='reseller_countries']" position="after">
<h3>World Map</h3> <h3>World Map</h3>
<ul class="nav"> <ul class="nav">
<iframe t-attf-src="/google_map/?width=260&amp;height=240&amp;partner_ids=#{ google_map_partner_ids }&amp;partner_url=/partners/" <iframe t-attf-src="/google_map?width=260&amp;height=240&amp;partner_ids=#{ google_map_partner_ids }&amp;partner_url=/partners/"
style="width:260px; height:260px; border:0; padding:0; margin:0;"></iframe> style="width:260px; height:260px; border:0; padding:0; margin:0;" scrolling="no"></iframe>
</ul> </ul>
</xpath> </xpath>
</template> </template>

View File

@ -59,8 +59,11 @@ class WebsiteCustomer(http.Controller):
partner_count = partner_obj.search_count(cr, openerp.SUPERUSER_ID, domain, context=request.context) partner_count = partner_obj.search_count(cr, openerp.SUPERUSER_ID, domain, context=request.context)
# pager # pager
url = '/customers/'
if country_id:
url += 'country/%s/' % country_id
pager = request.website.pager( pager = request.website.pager(
url="/customers", total=partner_count, page=page, step=self._references_per_page, url=url, total=partner_count, page=page, step=self._references_per_page,
scope=7, url_args=post scope=7, url_args=post
) )

View File

@ -68,9 +68,8 @@
<!-- Option: left column: World Map --> <!-- Option: left column: World Map -->
<template id="opt_country" inherit_option_id="website_customer.index" name="Show Map"> <template id="opt_country" inherit_option_id="website_customer.index" name="Show Map">
<xpath expr="//div[@id='ref_left_column']" position="inside"> <xpath expr="//div[@id='ref_left_column']" position="inside">
<iframe t-attf-src="/google_map?partner_ids=#{ google_map_partner_ids }&amp;partner_url=/customers/&amp;output=embed"
<iframe t-attf-src="/google_map/?partner_ids=#{ google_map_partner_ids }&amp;partner_url=/customers/&amp;output=embed" style="width:100%; border:0; padding:0; margin:0;" scrolling="no"></iframe>
style="width:100%; border:0; padding:0; margin:0;"></iframe>
</xpath> </xpath>
</template> </template>

View File

@ -100,9 +100,12 @@ class website_event(http.Controller):
if searches["type"] != 'all': if searches["type"] != 'all':
current_type = type_obj.browse(cr, uid, int(searches['type']), context=context) current_type = type_obj.browse(cr, uid, int(searches['type']), context=context)
domain_search["type"] = [("type", "=", int(searches["type"]))] domain_search["type"] = [("type", "=", int(searches["type"]))]
if searches["country"] != 'all':
if searches["country"] != 'all' and searches["country"] != 'online':
current_country = country_obj.browse(cr, uid, int(searches['country']), context=context) current_country = country_obj.browse(cr, uid, int(searches['country']), context=context)
domain_search["country"] = [("country_id", "=", int(searches["country"]))] domain_search["country"] = ['|', ("country_id", "=", int(searches["country"])), ("country_id", "=", False)]
elif searches["country"] == 'online':
domain_search["country"] = [("country_id", "=", False)]
def dom_without(without): def dom_without(without):
domain = [('state', "in", ['draft','confirm','done'])] domain = [('state', "in", ['draft','confirm','done'])]

View File

@ -51,6 +51,7 @@
<div itemscope="itemscope" itemtype="http://schema.org/Event" class="media-body"> <div itemscope="itemscope" itemtype="http://schema.org/Event" class="media-body">
<h4 class="media-heading"> <h4 class="media-heading">
<a itemprop="url" t-att-class="event.state == 'done' and 'text-success'" t-attf-href="/event/#{ slug(event) }/#{(not event.menu_id) and 'register' or ''}"><span itemprop="name" t-field="event.name"> </span></a> <a itemprop="url" t-att-class="event.state == 'done' and 'text-success'" t-attf-href="/event/#{ slug(event) }/#{(not event.menu_id) and 'register' or ''}"><span itemprop="name" t-field="event.name"> </span></a>
<small t-if="not event.address_id" class="label label-info">Online</small>
<small t-if="not event.website_published" class="label label-danger">not published</small> <small t-if="not event.website_published" class="label label-danger">not published</small>
</h4> </h4>
<div> <div>
@ -172,7 +173,13 @@
<ul class="nav nav-pills nav-stacked mt32"> <ul class="nav nav-pills nav-stacked mt32">
<t t-foreach="countries"> <t t-foreach="countries">
<li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''"> <li t-if="country_id" t-att-class="searches.get('country') == str(country_id and country_id[0]) and 'active' or ''">
<a t-attf-href="/event?{{ keep_query('type', 'data', country=country_id[0]) }}"><t t-esc="country_id[1]"/> <a t-attf-href="/event/?{{ keep_query('type', 'date', country=country_id[0]) }}"><t t-esc="country_id[1]"/>
<span class="badge pull-right"><t t-esc="country_id_count"/></span>
</a>
</li>
<li t-if="not country_id" t-att-class="searches.get('country') == 'online' and 'active' or ''">
<a t-attf-href="/event/?{{ keep_query('type', 'date', country='online') }}">
<span>Online Events</span>
<span class="badge pull-right"><t t-esc="country_id_count"/></span> <span class="badge pull-right"><t t-esc="country_id_count"/></span>
</a> </a>
</li> </li>