[MERGE] Forward-port of saas-5 up to 20cc18d

This commit is contained in:
Olivier Dony 2014-08-13 20:46:47 +02:00
commit e11eddf753
35 changed files with 188 additions and 122 deletions

View File

@ -114,7 +114,7 @@ class account_invoice(models.Model):
def _compute_residual(self): def _compute_residual(self):
nb_inv_in_partial_rec = max_invoice_id = 0 nb_inv_in_partial_rec = max_invoice_id = 0
self.residual = 0.0 self.residual = 0.0
for line in self.move_id.line_id: for line in self.sudo().move_id.line_id:
if line.account_id.type in ('receivable', 'payable'): if line.account_id.type in ('receivable', 'payable'):
if line.currency_id == self.currency_id: if line.currency_id == self.currency_id:
self.residual += line.amount_residual_currency self.residual += line.amount_residual_currency
@ -1397,8 +1397,7 @@ class account_invoice_line(models.Model):
res = [] res = []
for line in inv.invoice_line: for line in inv.invoice_line:
mres = self.move_line_get_item(line) mres = self.move_line_get_item(line)
if not mres: mres['invl_id'] = line.id
continue
res.append(mres) res.append(mres)
tax_code_found = False tax_code_found = False
taxes = line.invoice_line_tax_id.compute_all( taxes = line.invoice_line_tax_id.compute_all(

View File

@ -124,7 +124,7 @@ class account_invoice_line(osv.osv):
account_prec = decimal_precision.precision_get(cr, uid, 'Account') account_prec = decimal_precision.precision_get(cr, uid, 'Account')
# calculate and write down the possible price difference between invoice price and product price # calculate and write down the possible price difference between invoice price and product price
for line in res: for line in res:
if a == line['account_id'] and i_line.product_id.id == line['product_id']: if line.get('invl_id', 0) == i_line.id and a == line['account_id']:
uom = i_line.product_id.uos_id or i_line.product_id.uom_id uom = i_line.product_id.uos_id or i_line.product_id.uom_id
valuation_price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id) valuation_price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id)
if inv.currency_id.id != company_currency: if inv.currency_id.id != company_currency:

View File

@ -54,7 +54,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:
@ -63,7 +63,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

@ -237,8 +237,8 @@ class test_message_compose(TestMail):
email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, force_send=True, context=context) email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, force_send=True, context=context)
sent_emails = self._build_email_kwargs_list sent_emails = self._build_email_kwargs_list
email_to_lst = [ email_to_lst = [
['b@b.b', 'c@c.c'], ['"Administrator" <admin@yourcompany.example.com>'], ['b@b.b', 'c@c.c'], ['Administrator <admin@yourcompany.example.com>'],
['"Raoul Grosbedon" <raoul@raoul.fr>'], ['"Bert Tartignole" <bert@bert.fr>']] ['Raoul Grosbedon <raoul@raoul.fr>'], ['Bert Tartignole <bert@bert.fr>']]
self.assertEqual(len(sent_emails), 4, 'email_template: send_mail: 3 valid email recipients + email_to -> should send 4 emails') self.assertEqual(len(sent_emails), 4, 'email_template: send_mail: 3 valid email recipients + email_to -> should send 4 emails')
for email in sent_emails: for email in sent_emails:
self.assertIn(email['email_to'], email_to_lst, 'email_template: send_mail: wrong email_recipients') self.assertIn(email['email_to'], email_to_lst, 'email_template: send_mail: wrong email_recipients')

View File

@ -468,7 +468,7 @@
<field name="expiration_date" /> <field name="expiration_date" />
</group> </group>
<group> <group>
<field name="insurer_id" /> <field name="insurer_id" context="{'default_supplier': True}"/>
<field name="purchaser_id" /> <field name="purchaser_id" />
<field name="ins_ref" /> <field name="ins_ref" />
</group> </group>
@ -676,7 +676,7 @@
<field name="date" /> <field name="date" />
<field name="purchaser_id" /> <field name="purchaser_id" />
<field name="inv_ref" /> <field name="inv_ref" />
<field name="vendor_id" /> <field name="vendor_id" context="{'default_supplier': True}"/>
</group> </group>
</group> </group>
<group string="Notes"> <group string="Notes">
@ -778,7 +778,7 @@
<group string="Additional Details"> <group string="Additional Details">
<field name="date" /> <field name="date" />
<field name="purchaser_id" /> <field name="purchaser_id" />
<field name="vendor_id" /> <field name="vendor_id" context="{'default_supplier': True}"/>
<field name="inv_ref" /> <field name="inv_ref" />
</group> </group>
</group> </group>

View File

@ -194,7 +194,7 @@ class gamification_goal(osv.Model):
_columns = { _columns = {
'definition_id': fields.many2one('gamification.goal.definition', string='Goal Definition', required=True, ondelete="cascade"), 'definition_id': fields.many2one('gamification.goal.definition', string='Goal Definition', required=True, ondelete="cascade"),
'user_id': fields.many2one('res.users', string='User', required=True), 'user_id': fields.many2one('res.users', string='User', required=True, auto_join=True),
'line_id': fields.many2one('gamification.challenge.line', string='Challenge Line', ondelete="cascade"), 'line_id': fields.many2one('gamification.challenge.line', string='Challenge Line', ondelete="cascade"),
'challenge_id': fields.related('line_id', 'challenge_id', 'challenge_id': fields.related('line_id', 'challenge_id',
string="Challenge", string="Challenge",
@ -239,7 +239,7 @@ class gamification_goal(osv.Model):
'state': 'draft', 'state': 'draft',
'start_date': fields.date.today, 'start_date': fields.date.today,
} }
_order = 'create_date desc, end_date desc, definition_id, id' _order = 'start_date desc, end_date desc, definition_id, id'
def _check_remind_delay(self, cr, uid, goal, context=None): def _check_remind_delay(self, cr, uid, goal, context=None):
"""Verify if a goal has not been updated for some time and send a """Verify if a goal has not been updated for some time and send a

View File

@ -40,7 +40,7 @@ class account_coda_import(osv.osv_memory):
} }
_defaults = { _defaults = {
'coda_fname': lambda *a: '', 'coda_fname': 'coda.txt',
} }
def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None): def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):

View File

@ -21,6 +21,7 @@
import base64 import base64
import logging import logging
from email.utils import formataddr
from urlparse import urljoin from urlparse import urljoin
from openerp import api, tools from openerp import api, tools
@ -184,11 +185,10 @@ class mail_mail(osv.Model):
def send_get_mail_to(self, cr, uid, mail, partner=None, context=None): def send_get_mail_to(self, cr, uid, mail, partner=None, context=None):
"""Forge the email_to with the following heuristic: """Forge the email_to with the following heuristic:
- if 'partner' and mail is a notification on a document: followers (Followers of 'Doc' <email>) - if 'partner', 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: if 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

@ -24,6 +24,7 @@ import logging
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, api from openerp import SUPERUSER_ID, api
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
@ -170,9 +171,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):

View File

@ -37,6 +37,7 @@ import time
import xmlrpclib import xmlrpclib
import re import re
from email.message import Message from email.message import Message
from email.utils import formataddr
from urllib import urlencode from urllib import urlencode
from openerp import api, tools from openerp import api, tools
@ -722,12 +723,10 @@ class mail_thread(osv.AbstractModel):
aliases.update(dict((res_id, '%s@%s' % (catchall_alias, alias_domain)) for res_id in left_ids)) aliases.update(dict((res_id, '%s@%s' % (catchall_alias, alias_domain)) for res_id in left_ids))
# compute name of reply-to # compute name of reply-to
company_name = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).company_id.name company_name = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).company_id.name
res.update( for res_id in aliases.keys():
dict((res_id, '"%(company_name)s%(document_name)s" <%(email)s>' % email_name = '%s%s' % (company_name, doc_names.get(res_id) and (' ' + doc_names[res_id]) or '')
{'company_name': company_name, email_addr = aliases[res_id]
'document_name': doc_names.get(res_id) and ' ' + re.sub(r'[^\w+.]+', '-', doc_names[res_id]) or '', res[res_id] = formataddr((email_name, email_addr))
'email': aliases[res_id]
} or False) for res_id in aliases.keys()))
left_ids = set(ids).difference(set(aliases.keys())) left_ids = set(ids).difference(set(aliases.keys()))
if left_ids and default: if left_ids and default:
res.update(dict((res_id, default) for res_id in left_ids)) res.update(dict((res_id, default) for res_id in left_ids))

View File

@ -448,7 +448,7 @@ class test_mail(TestMail):
'message_post: mail.mail notifications should have been auto-deleted!') 'message_post: mail.mail notifications should have been auto-deleted!')
# 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 = ['"Followers of -Pigs-" <a@a>', '"Followers of -Pigs-" <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')
@ -461,7 +461,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'], '"YourCompany -Pigs-" <group+pigs@schlouby.fr>', self.assertEqual(sent_email['reply_to'], u'"YourCompany \\"Pigs\\" !ù $%-" <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')
@ -518,7 +518,7 @@ class test_mail(TestMail):
self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg2_id)]), 'mail.mail notifications should have been auto-deleted!') self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg2_id)]), 'mail.mail notifications should have been auto-deleted!')
# 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:

View File

@ -81,7 +81,7 @@ 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_alias = '"YourCompany Pigs" <group+pigs@schlouby.fr>' raoul_reply_alias = 'YourCompany Pigs <group+pigs@schlouby.fr>'
# -------------------------------------------------- # --------------------------------------------------
# Case1: without alias_domain # Case1: without alias_domain
@ -151,7 +151,7 @@ class TestMailMessage(TestMail):
msg_id = self.mail_message.create(cr, user_raoul_id, {}) msg_id = self.mail_message.create(cr, user_raoul_id, {})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id) msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: generated reply_to # Test: generated reply_to
self.assertEqual(msg.reply_to, '"YourCompany" <gateway@schlouby.fr>', self.assertEqual(msg.reply_to, 'YourCompany <gateway@schlouby.fr>',
'mail_mail: reply_to should equal the catchall email alias') 'mail_mail: reply_to should equal the catchall email alias')
# Do: create a mail_mail # Do: create a mail_mail

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

@ -902,7 +902,7 @@
<br /> <br />
<t t-esc="widget.pos.company.name"/><br /> <t t-esc="widget.pos.company.name"/><br />
Phone: <t t-esc="widget.pos.company.phone || ''"/><br /> Phone: <t t-esc="widget.pos.company.phone || ''"/><br />
User: <t t-esc="widget.pos.cashier.name"/><br /> User: <t t-esc="widget.pos.cashier ? widget.pos.cashier.name : widget.pos.user.name"/><br />
Shop: <t t-esc="widget.pos.shop.name"/><br /> Shop: <t t-esc="widget.pos.shop.name"/><br />
<br /> <br />
<t t-if="widget.pos.config.receipt_header"> <t t-if="widget.pos.config.receipt_header">

View File

@ -21,6 +21,7 @@
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.osv import osv, fields from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
class sale_order(osv.Model): class sale_order(osv.Model):
@ -36,7 +37,7 @@ class sale_order(osv.Model):
def _portal_payment_block(self, cr, uid, ids, fieldname, arg, context=None): def _portal_payment_block(self, cr, uid, ids, fieldname, arg, context=None):
result = dict.fromkeys(ids, False) result = dict.fromkeys(ids, False)
payment_acquirer = self.pool['payment.acquirer'] payment_acquirer = self.pool['payment.acquirer']
for this in self.browse(cr, uid, ids, context=context): for this in self.browse(cr, SUPERUSER_ID, ids, context=context):
if this.state not in ('draft', 'cancel') and not this.invoiced: if this.state not in ('draft', 'cancel') and not this.invoiced:
result[this.id] = payment_acquirer.render_payment_block( result[this.id] = payment_acquirer.render_payment_block(
cr, uid, this.name, this.amount_total, this.pricelist_id.currency_id.id, cr, uid, this.name, this.amount_total, this.pricelist_id.currency_id.id,

View File

@ -5,16 +5,8 @@ access_account_invoice,account.invoice,account.model_account_invoice,base.group_
access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,base.group_portal,1,0,0,0 access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,base.group_portal,1,0,0,0
access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,base.group_portal,1,0,0,0 access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,base.group_portal,1,0,0,0
access_account_journal,account.journal,account.model_account_journal,base.group_portal,1,0,0,0 access_account_journal,account.journal,account.model_account_journal,base.group_portal,1,0,0,0
access_account_voucher,account.voucher,account_voucher.model_account_voucher,base.group_portal,1,0,0,0 access_sale_shop,sale.shop,sale.model_sale_shop,base.group_portal,1,0,0,0
access_account_voucher_line,account.voucher.line,account_voucher.model_account_voucher_line,base.group_portal,1,0,0,0
access_account_move,account.move,account.model_account_move,base.group_portal,1,0,0,0
access_account_move_line,account.move.line,account.model_account_move_line,base.group_portal,1,0,0,0
access_account_move_reconcile,account.move.reconcile,account.model_account_move_reconcile,base.group_portal,1,0,0,0
access_account_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,base.group_portal,1,0,0,0
access_product_list,product.pricelist,product.model_product_pricelist,base.group_portal,1,0,0,0 access_product_list,product.pricelist,product.model_product_pricelist,base.group_portal,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,base.group_portal,1,0,0,0 access_res_partner,res.partner,base.model_res_partner,base.group_portal,1,0,0,0
access_account_tax,account.tax,account.model_account_tax,base.group_portal,1,0,0,0 access_account_tax,account.tax,account.model_account_tax,base.group_portal,1,0,0,0
access_account_fiscalyear,account.fiscalyear,account.model_account_fiscalyear,base.group_portal,1,0,0,0
access_res_partner_category,res.partner.category,base.model_res_partner_category,base.group_portal,1,0,0,0 access_res_partner_category,res.partner.category,base.model_res_partner_category,base.group_portal,1,0,0,0
access_account_period,account.period,account.model_account_period,base.group_portal,1,0,0,0
access_account_account,account.account,account.model_account_account,base.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
5 access_account_invoice_tax account.invoice.tax account.model_account_invoice_tax base.group_portal 1 0 0 0
6 access_account_invoice_line account.invoice.line account.model_account_invoice_line base.group_portal 1 0 0 0
7 access_account_journal account.journal account.model_account_journal base.group_portal 1 0 0 0
8 access_account_voucher access_sale_shop account.voucher sale.shop account_voucher.model_account_voucher sale.model_sale_shop base.group_portal 1 0 0 0
access_account_voucher_line account.voucher.line account_voucher.model_account_voucher_line base.group_portal 1 0 0 0
access_account_move account.move account.model_account_move base.group_portal 1 0 0 0
access_account_move_line account.move.line account.model_account_move_line base.group_portal 1 0 0 0
access_account_move_reconcile account.move.reconcile account.model_account_move_reconcile base.group_portal 1 0 0 0
access_account_fiscalyear account.sequence.fiscalyear account.model_account_sequence_fiscalyear base.group_portal 1 0 0 0
9 access_product_list product.pricelist product.model_product_pricelist base.group_portal 1 0 0 0
10 access_res_partner res.partner base.model_res_partner base.group_portal 1 0 0 0
11 access_account_tax account.tax account.model_account_tax base.group_portal 1 0 0 0
access_account_fiscalyear account.fiscalyear account.model_account_fiscalyear base.group_portal 1 0 0 0
12 access_res_partner_category res.partner.category base.model_res_partner_category base.group_portal 1 0 0 0
access_account_period account.period account.model_account_period base.group_portal 1 0 0 0
access_account_account account.account account.model_account_account base.group_portal 1 0 0 0

View File

@ -18,7 +18,7 @@ their documents through the portal.</field>
<record id="portal_sale_order_user_rule" model="ir.rule"> <record id="portal_sale_order_user_rule" model="ir.rule">
<field name="name">Portal Personal Quotations/Sales Orders</field> <field name="name">Portal Personal Quotations/Sales Orders</field>
<field name="model_id" ref="sale.model_sale_order"/> <field name="model_id" ref="sale.model_sale_order"/>
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field> <field name="domain_force">[('message_follower_ids','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/> <field name="groups" eval="[(4, ref('base.group_portal'))]"/>
<field eval="1" name="perm_unlink"/> <field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/> <field eval="1" name="perm_write"/>
@ -26,17 +26,32 @@ their documents through the portal.</field>
<field eval="0" name="perm_create"/> <field eval="0" name="perm_create"/>
</record> </record>
<record id="portal_sale_order_line_rule" model="ir.rule">
<field name="name">Portal Sales Orders Line</field>
<field name="model_id" ref="sale.model_sale_order_line"/>
<field name="domain_force">[('order_id.message_follower_ids','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record id="portal_account_invoice_user_rule" model="ir.rule"> <record id="portal_account_invoice_user_rule" model="ir.rule">
<field name="name">Portal Personal Account Invoices</field> <field name="name">Portal Personal Account Invoices</field>
<field name="model_id" ref="account.model_account_invoice"/> <field name="model_id" ref="account.model_account_invoice"/>
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field> <field name="domain_force">[('message_follower_ids','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record id="portal_account_invoice_line_rule" model="ir.rule">
<field name="name">Portal Invoice Lines</field>
<field name="model_id" ref="account.model_account_invoice_line"/>
<field name="domain_force">[('invoice_id.message_follower_ids','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/> <field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record> </record>
<record id="portal_personal_contact" model="ir.rule"> <record id="portal_personal_contact" model="ir.rule">
<field name="name">Portal Personal Contacts</field> <field name="name">Portal Personal Contacts</field>
<field name="model_id" ref="base.model_res_partner"/> <field name="model_id" ref="base.model_res_partner"/>
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field> <field name="domain_force">[('message_follower_ids','in',[user.commercial_partner_id.id])]</field>
<field eval="0" name="perm_read"/> <field eval="0" name="perm_read"/>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/> <field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record> </record>

View File

@ -20,6 +20,7 @@
############################################################################## ##############################################################################
import time import time
from psycopg2 import OperationalError
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from openerp.osv import fields, osv from openerp.osv import fields, osv
@ -193,31 +194,49 @@ class procurement_order(osv.osv):
def reset_to_confirmed(self, cr, uid, ids, context=None): def reset_to_confirmed(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state': 'confirmed'}, context=context) return self.write(cr, uid, ids, {'state': 'confirmed'}, context=context)
def run(self, cr, uid, ids, context=None): def run(self, cr, uid, ids, autocommit=False, context=None):
for procurement_id in ids: for procurement_id in ids:
#we intentionnaly do the browse under the for loop to avoid caching all ids which would be resource greedy #we intentionnaly do the browse under the for loop to avoid caching all ids which would be resource greedy
#and useless as we'll make a refresh later that will invalidate all the cache (and thus the next iteration #and useless as we'll make a refresh later that will invalidate all the cache (and thus the next iteration
#will fetch all the ids again) #will fetch all the ids again)
procurement = self.browse(cr, uid, procurement_id, context=context) procurement = self.browse(cr, uid, procurement_id, context=context)
if procurement.state not in ("running", "done"): if procurement.state not in ("running", "done"):
if self._assign(cr, uid, procurement, context=context): try:
procurement.refresh() if self._assign(cr, uid, procurement, context=context):
res = self._run(cr, uid, procurement, context=context or {}) procurement.refresh()
if res: res = self._run(cr, uid, procurement, context=context or {})
self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context) if res:
self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context)
else:
self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context)
else: else:
self.message_post(cr, uid, [procurement.id], body=_('No rule matching this procurement'), context=context)
self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context)
else: if autocommit:
self.message_post(cr, uid, [procurement.id], body=_('No rule matching this procurement'), context=context) cr.commit()
self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) except OperationalError:
if autocommit:
cr.rollback()
continue
else:
raise
return True return True
def check(self, cr, uid, ids, context=None): def check(self, cr, uid, ids, autocommit=False, context=None):
done_ids = [] done_ids = []
for procurement in self.browse(cr, uid, ids, context=context): for procurement in self.browse(cr, uid, ids, context=context):
result = self._check(cr, uid, procurement, context=context) try:
if result: result = self._check(cr, uid, procurement, context=context)
done_ids.append(procurement.id) if result:
done_ids.append(procurement.id)
if autocommit:
cr.commit()
except OperationalError:
if autocommit:
cr.rollback()
continue
else:
raise
if done_ids: if done_ids:
self.write(cr, uid, done_ids, {'state': 'done'}, context=context) self.write(cr, uid, done_ids, {'state': 'done'}, context=context)
return done_ids return done_ids
@ -291,11 +310,14 @@ class procurement_order(osv.osv):
dom = [('state', '=', 'confirmed')] dom = [('state', '=', 'confirmed')]
if company_id: if company_id:
dom += [('company_id', '=', company_id)] dom += [('company_id', '=', company_id)]
prev_ids = []
while True: while True:
ids = self.search(cr, SUPERUSER_ID, dom, context=context) ids = self.search(cr, SUPERUSER_ID, dom, context=context)
if not ids: if not ids or prev_ids == ids:
break break
self.run(cr, SUPERUSER_ID, ids, context=context) else:
prev_ids = ids
self.run(cr, SUPERUSER_ID, ids, autocommit=use_new_cursor, context=context)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
@ -304,12 +326,14 @@ class procurement_order(osv.osv):
dom = [('state', '=', 'running')] dom = [('state', '=', 'running')]
if company_id: if company_id:
dom += [('company_id', '=', company_id)] dom += [('company_id', '=', company_id)]
prev_ids = []
while True: while True:
ids = self.search(cr, SUPERUSER_ID, dom, offset=offset, context=context) ids = self.search(cr, SUPERUSER_ID, dom, offset=offset, context=context)
if not ids: if not ids or prev_ids == ids:
break break
done = self.check(cr, SUPERUSER_ID, ids, context=context) else:
offset += len(ids) - len(done) prev_ids = ids
self.check(cr, SUPERUSER_ID, ids, autocommit=use_new_cursor, context=context)
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()

View File

@ -26,6 +26,7 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FO
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from datetime import datetime from datetime import datetime
from psycopg2 import OperationalError
import openerp import openerp
class procurement_group(osv.osv): class procurement_group(osv.osv):
@ -204,8 +205,8 @@ class procurement_order(osv.osv):
return True return True
return super(procurement_order, self)._run(cr, uid, procurement, context=context) return super(procurement_order, self)._run(cr, uid, procurement, context=context)
def run(self, cr, uid, ids, context=None): def run(self, cr, uid, ids, autocommit=False, context=None):
res = super(procurement_order, self).run(cr, uid, ids, context=context) res = super(procurement_order, self).run(cr, uid, ids, autocommit=autocommit, context=context)
#after all the procurements are run, check if some created a draft stock move that needs to be confirmed #after all the procurements are run, check if some created a draft stock move that needs to be confirmed
#(we do that in batch because it fasts the picking assignation and the picking state computation) #(we do that in batch because it fasts the picking assignation and the picking state computation)
move_to_confirm_ids = [] move_to_confirm_ids = []
@ -335,36 +336,51 @@ 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]
dom = company_id and [('company_id', '=', company_id)] or [] dom = company_id and [('company_id', '=', company_id)] or []
while ids: orderpoint_ids = orderpoint_obj.search(cr, uid, dom)
ids = orderpoint_obj.search(cr, uid, dom, offset=offset, limit=100) prev_ids = []
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 prods < op.product_min_qty:
qty = max(op.product_min_qty, op.product_max_qty) - prods
qty -= orderpoint_obj.subtract_procurements(cr, uid, op, context=context) reste = qty % op.qty_multiple
if reste > 0:
qty += op.qty_multiple - reste
if qty > 0: if qty <= 0:
proc_id = procurement_obj.create(cr, uid, continue
self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context),
context=context) qty -= orderpoint_obj.subtract_procurements(cr, uid, op, context=context)
self.check(cr, uid, [proc_id])
self.run(cr, uid, [proc_id]) if qty > 0:
offset += len(ids) proc_id = procurement_obj.create(cr, uid,
self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context),
context=context)
self.check(cr, uid, [proc_id])
self.run(cr, uid, [proc_id])
if use_new_cursor:
cr.commit()
except OperationalError:
if use_new_cursor:
orderpoint_ids.append(op.id)
cr.rollback()
continue
else:
raise
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
if prev_ids == ids:
break
else:
prev_ids = ids
if use_new_cursor: if use_new_cursor:
cr.commit() cr.commit()
cr.close() cr.close()

View File

@ -1418,16 +1418,18 @@ class ExportFormat(object):
raise NotImplementedError() raise NotImplementedError()
def base(self, data, token): def base(self, data, token):
params = simplejson.loads(data)
model, fields, ids, domain, import_compat = \ model, fields, ids, domain, import_compat = \
operator.itemgetter('model', 'fields', 'ids', 'domain', operator.itemgetter('model', 'fields', 'ids', 'domain',
'import_compat')( 'import_compat')(
simplejson.loads(data)) params)
Model = request.session.model(model) Model = request.session.model(model)
ids = ids or Model.search(domain, 0, False, False, request.context) context = dict(req.context or {}, **params.get('context', {}))
ids = ids or Model.search(domain, 0, False, False, context)
field_names = map(operator.itemgetter('name'), fields) field_names = map(operator.itemgetter('name'), fields)
import_data = Model.export_data(ids, field_names, self.raw_data, context=request.context).get('datas',[]) import_data = Model.export_data(ids, field_names, self.raw_data, context=context).get('datas',[])
if import_compat: if import_compat:
columns_headers = field_names columns_headers = field_names

View File

@ -406,6 +406,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
fields: exported_fields, fields: exported_fields,
ids: this.ids_to_export, ids: this.ids_to_export,
domain: this.domain, domain: this.domain,
context: this.dataset.context,
import_compat: !!this.$el.find("#import_compat").val(), import_compat: !!this.$el.find("#import_compat").val(),
})}, })},
complete: instance.web.unblockUI, complete: instance.web.unblockUI,

View File

@ -487,7 +487,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
*/ */
setup_global_completion: function () { setup_global_completion: function () {
var self = this; var self = this;
this.autocomplete = new instance.web.search.AutoComplete(this, { this.autocomplete = new instance.web.search.AutoComplete(this, {
source: this.proxy('complete_global_search'), source: this.proxy('complete_global_search'),
select: this.proxy('select_completion'), select: this.proxy('select_completion'),

View File

@ -522,7 +522,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
self.dataset.index = 0; self.dataset.index = 0;
} }
} else if (self.dataset.index >= self.records.length) { } else if (self.dataset.index >= self.records.length) {
self.dataset.index = 0; self.dataset.index = self.records.length ? 0 : null;
} }
self.compute_aggregates(); self.compute_aggregates();

View File

@ -423,14 +423,15 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
attrs.value = [attrs.value]; attrs.value = [attrs.value];
} }
attrs.value = _.range(grouped_on.length).map(function (i) { attrs.value = _.range(grouped_on.length).map(function (i) {
var grp = grouped_on[i],
field = self.fields[grp];
if (attrs.value[i] === false) { if (attrs.value[i] === false) {
return _t('Undefined'); return _t('Undefined');
} else if (attrs.value[i] instanceof Array) { } else if (attrs.value[i] instanceof Array) {
return attrs.value[i][1]; return attrs.value[i][1];
}else if (grouped_on && self.fields[grouped_on].type === 'selection'){ } else if (field && field.type === 'selection') {
var selection = self.fields[grouped_on].selection; var selected = _.where(field.selection, {0: attrs.value[i]})[0];
var value_lookup = _.where(selection, {0:attrs.value[i]}); return selected ? selected[1] : attrs.value[i];
return value_lookup ? value_lookup[0][1] : _t('Undefined');
} }
return attrs.value[i]; return attrs.value[i];
}); });

View File

@ -310,6 +310,8 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
var kgroup = new instance.web_kanban.KanbanGroup(self, records, null, self.dataset); var kgroup = new instance.web_kanban.KanbanGroup(self, records, null, self.dataset);
if (!_.isEmpty(self.dataset.ids) && (self.dataset.index === null || self.dataset.index >= self.dataset.ids.length)) { if (!_.isEmpty(self.dataset.ids) && (self.dataset.index === null || self.dataset.index >= self.dataset.ids.length)) {
self.dataset.index = 0; self.dataset.index = 0;
} else if (_.isEmpty(self.dataset.ids)){
self.dataset.index = null;
} }
self.do_add_groups([kgroup]).done(function() { self.do_add_groups([kgroup]).done(function() {
if (_.isEmpty(records)) { if (_.isEmpty(records)) {

View File

@ -131,8 +131,8 @@
<!-- modal end --> <!-- modal end -->
<h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".partner_map_modal"><span class="fa fa-external-link" /></button></h3> <h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".partner_map_modal"><span class="fa fa-external-link" /></button></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:240px; border:0; padding:0; margin:0;"></iframe> style="width:260px; height:240px; 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

@ -84,8 +84,8 @@
<!-- modal end --> <!-- modal end -->
<h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".customer_map_modal"><span class="fa fa-external-link" /></button></h3> <h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".customer_map_modal"><span class="fa fa-external-link" /></button></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=/customers/" <iframe t-attf-src="/google_map?width=260&amp;height=240&amp;partner_ids=#{ google_map_partner_ids }&amp;partner_url=/customers/"
style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe> style="width:260px; height:240px; border:0; padding:0; margin:0;" scrolling="no"></iframe>
</ul> </ul>
</xpath> </xpath>
</template> </template>

View File

@ -90,9 +90,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

@ -57,6 +57,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>
@ -179,7 +180,13 @@
<ul class="nav nav-pills nav-stacked mt32"> <ul class="nav nav-pills nav-stacked mt32">
<t t-foreach="countries" t-as="country"> <t t-foreach="countries" t-as="country">
<li t-if="country['country_id']" t-att-class="searches.get('country') == str(country['country_id'] and country['country_id'][0]) and 'active' or ''"> <li t-if="country['country_id']" t-att-class="searches.get('country') == str(country['country_id'] and country['country_id'][0]) and 'active' or ''">
<a t-attf-href="/event?{{ keep_query('type', 'data', country=country['country_id'][0]) }}"><t t-esc="country['country_id'][1]"/> <a t-attf-href="/event?{{ keep_query('type', 'date', country=country['country_id'][0]) }}"><t t-esc="country['country_id'][1]"/>
<span class="badge pull-right"><t t-esc="country['country_id_count']"/></span>
</a>
</li>
<li t-if="not country['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['country_id_count']"/></span> <span class="badge pull-right"><t t-esc="country['country_id_count']"/></span>
</a> </a>
</li> </li>

View File

@ -29,19 +29,18 @@
<h4>Choose your Delivery Method</h4> <h4>Choose your Delivery Method</h4>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li t-foreach="deliveries" t-as="delivery"> <li t-foreach="deliveries" t-as="delivery">
<label> <t t-if="delivery.available">
<input t-att-value="delivery.id" type="radio" name="delivery_type" <label>
t-att-checked="order.carrier_id and order.carrier_id.id == delivery.id and 'checked' or False" <input t-att-value="delivery.id" type="radio" name="delivery_type"
t-att-disabled="delivery.available and '0' or '1'"/> t-att-checked="order.carrier_id and order.carrier_id.id == delivery.id and 'checked' or False"/>
<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> </t>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -160,8 +160,8 @@ class ir_cron(osv.osv):
""" """
try: try:
with api.Environment.manage(): with api.Environment.manage():
now = fields.datetime.context_timestamp(job_cr, SUPERUSER_ID, datetime.now()) now = fields.datetime.context_timestamp(job_cr, job['user_id'], datetime.now())
nextcall = fields.datetime.context_timestamp(job_cr, SUPERUSER_ID, datetime.strptime(job['nextcall'], DEFAULT_SERVER_DATETIME_FORMAT)) nextcall = fields.datetime.context_timestamp(job_cr, job['user_id'], datetime.strptime(job['nextcall'], DEFAULT_SERVER_DATETIME_FORMAT))
numbercall = job['numbercall'] numbercall = job['numbercall']
ok = False ok = False

View File

@ -31,7 +31,6 @@
<group col="4"> <group col="4">
<field name="name"/> <field name="name"/>
<field name="shortcut"/> <field name="shortcut"/>
<field name="domain"/>
</group> </group>
</form> </form>
</field> </field>
@ -183,8 +182,7 @@
<field name="fax"/> <field name="fax"/>
<field name="user_ids" invisible="1"/> <field name="user_ids" invisible="1"/>
<field name="email" widget="email" attrs="{'required': [('user_ids','!=', [])]}"/> <field name="email" widget="email" attrs="{'required': [('user_ids','!=', [])]}"/>
<field name="title" domain="[('domain','=','contact')]" options='{"no_open": True}' attrs="{'invisible': [('is_company','=',True)]}" context="{'default_domain': 'contact'}"/> <field name="title" domain="[('domain', '=', 'contact')]" options='{"no_open": True}'/>
<field name="title" domain="[('domain','=','partner')]" options='{"no_open": True}' attrs="{'invisible': [('is_company','=',False)]}" context="{'default_domain': 'partner'}"/>
</group> </group>
</group> </group>

View File

@ -3168,6 +3168,11 @@ class BaseModel(object):
env = self.env env = self.env
cr, user, context = env.args cr, user, context = env.args
# FIXME: The query construction needs to be rewritten using the internal Query
# object, as in search(), to avoid ambiguous column references when
# reading/sorting on a table that is auto_joined to another table with
# common columns (e.g. the magical columns)
# Construct a clause for the security rules. # Construct a clause for the security rules.
# 'tables' holds the list of tables necessary for the SELECT, including # 'tables' holds the list of tables necessary for the SELECT, including
# the ir.rule clauses, and contains at least self._table. # the ir.rule clauses, and contains at least self._table.

View File

@ -466,17 +466,16 @@ class datetime(_column):
registry = openerp.modules.registry.RegistryManager.get(cr.dbname) registry = openerp.modules.registry.RegistryManager.get(cr.dbname)
user = registry['res.users'].browse(cr, SUPERUSER_ID, uid) user = registry['res.users'].browse(cr, SUPERUSER_ID, uid)
tz_name = user.tz tz_name = user.tz
utc_timestamp = pytz.utc.localize(timestamp, is_dst=False) # UTC = no DST
if tz_name: if tz_name:
try: try:
utc = pytz.utc
context_tz = pytz.timezone(tz_name) context_tz = pytz.timezone(tz_name)
utc_timestamp = utc.localize(timestamp, is_dst=False) # UTC = no DST
return utc_timestamp.astimezone(context_tz) return utc_timestamp.astimezone(context_tz)
except Exception: except Exception:
_logger.debug("failed to compute context/client-specific timestamp, " _logger.debug("failed to compute context/client-specific timestamp, "
"using the UTC value", "using the UTC value",
exc_info=True) exc_info=True)
return timestamp return utc_timestamp
class binary(_column): class binary(_column):
_type = 'binary' _type = 'binary'