[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):
nb_inv_in_partial_rec = max_invoice_id = 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.currency_id == self.currency_id:
self.residual += line.amount_residual_currency
@ -1397,8 +1397,7 @@ class account_invoice_line(models.Model):
res = []
for line in inv.invoice_line:
mres = self.move_line_get_item(line)
if not mres:
continue
mres['invl_id'] = line.id
res.append(mres)
tax_code_found = False
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')
# calculate and write down the possible price difference between invoice price and product price
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
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:

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
@http.route('/calendar/notify', type='json', auth="none")
def notify(self):
registry = openerp.modules.registry.RegistryManager.get(request.session.db)
registry = request.registry
uid = request.session.uid
context = request.session.context
with registry.cursor() as cr:
@ -63,7 +63,7 @@ class meeting_invitation(http.Controller):
@http.route('/calendar/notify_ack', type='json', auth="none")
def notify_ack(self, type=''):
registry = openerp.modules.registry.RegistryManager.get(request.session.db)
registry = request.registry
uid = request.session.uid
context = request.session.context
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)
sent_emails = self._build_email_kwargs_list
email_to_lst = [
['b@b.b', 'c@c.c'], ['"Administrator" <admin@yourcompany.example.com>'],
['"Raoul Grosbedon" <raoul@raoul.fr>'], ['"Bert Tartignole" <bert@bert.fr>']]
['b@b.b', 'c@c.c'], ['Administrator <admin@yourcompany.example.com>'],
['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')
for email in sent_emails:
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" />
</group>
<group>
<field name="insurer_id" />
<field name="insurer_id" context="{'default_supplier': True}"/>
<field name="purchaser_id" />
<field name="ins_ref" />
</group>
@ -676,7 +676,7 @@
<field name="date" />
<field name="purchaser_id" />
<field name="inv_ref" />
<field name="vendor_id" />
<field name="vendor_id" context="{'default_supplier': True}"/>
</group>
</group>
<group string="Notes">
@ -778,7 +778,7 @@
<group string="Additional Details">
<field name="date" />
<field name="purchaser_id" />
<field name="vendor_id" />
<field name="vendor_id" context="{'default_supplier': True}"/>
<field name="inv_ref" />
</group>
</group>

View File

@ -194,7 +194,7 @@ class gamification_goal(osv.Model):
_columns = {
'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"),
'challenge_id': fields.related('line_id', 'challenge_id',
string="Challenge",
@ -239,7 +239,7 @@ class gamification_goal(osv.Model):
'state': 'draft',
'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):
"""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 = {
'coda_fname': lambda *a: '',
'coda_fname': 'coda.txt',
}
def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):

View File

@ -21,6 +21,7 @@
import base64
import logging
from email.utils import formataddr
from urlparse import urljoin
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):
"""Forge the email_to with the following heuristic:
- if 'partner' and mail is a notification on a document: followers (Followers of 'Doc' <email>)
- elif 'partner', no notificatoin or no doc: recipient specific (Partner Name <email>)
- if 'partner', recipient specific (Partner Name <email>)
- else fallback on mail.email_to splitting """
if partner:
email_to = ['"%s" <%s>' % (partner.name, partner.email)]
email_to = [formataddr((partner.name, partner.email))]
else:
email_to = tools.email_split(mail.email_to)
return email_to

View File

@ -24,6 +24,7 @@ import logging
from openerp import tools
from email.header import decode_header
from email.utils import formataddr
from openerp import SUPERUSER_ID, api
from openerp.osv import osv, orm, fields
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):
this = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
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:
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."))
def _get_default_author(self, cr, uid, context=None):

View File

@ -37,6 +37,7 @@ import time
import xmlrpclib
import re
from email.message import Message
from email.utils import formataddr
from urllib import urlencode
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))
# compute name of reply-to
company_name = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).company_id.name
res.update(
dict((res_id, '"%(company_name)s%(document_name)s" <%(email)s>' %
{'company_name': company_name,
'document_name': doc_names.get(res_id) and ' ' + re.sub(r'[^\w+.]+', '-', doc_names[res_id]) or '',
'email': aliases[res_id]
} or False) for res_id in aliases.keys()))
for res_id in aliases.keys():
email_name = '%s%s' % (company_name, doc_names.get(res_id) and (' ' + doc_names[res_id]) or '')
email_addr = aliases[res_id]
res[res_id] = formataddr((email_name, email_addr))
left_ids = set(ids).difference(set(aliases.keys()))
if left_ids and default:
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!')
# 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>']
self.assertEqual(len(sent_emails), 2,
'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')
self.assertIn(sent_email['email_to'][0], test_emailto,
'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')
self.assertEqual(_subject, sent_email['subject'],
'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!')
# 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>']
# self.assertEqual(len(sent_emails), 3, 'sent_email number of sent emails incorrect')
for sent_email in sent_emails:

View File

@ -81,7 +81,7 @@ class TestMailMessage(TestMail):
alias_domain = 'schlouby.fr'
raoul_from = 'Raoul Grosbedon <raoul@raoul.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
@ -151,7 +151,7 @@ class TestMailMessage(TestMail):
msg_id = self.mail_message.create(cr, user_raoul_id, {})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# 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')
# Do: create a mail_mail

View File

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

View File

@ -902,7 +902,7 @@
<br />
<t t-esc="widget.pos.company.name"/><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 />
<br />
<t t-if="widget.pos.config.receipt_header">

View File

@ -21,6 +21,7 @@
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
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):
result = dict.fromkeys(ids, False)
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:
result[this.id] = payment_acquirer.render_payment_block(
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_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_voucher,account.voucher,account_voucher.model_account_voucher,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_sale_shop,sale.shop,sale.model_sale_shop,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_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_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">
<field name="name">Portal Personal Quotations/Sales Orders</field>
<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 eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
@ -26,17 +26,32 @@ their documents through the portal.</field>
<field eval="0" name="perm_create"/>
</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">
<field name="name">Portal Personal Account Invoices</field>
<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'))]"/>
</record>
<record id="portal_personal_contact" model="ir.rule">
<field name="name">Portal Personal Contacts</field>
<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 name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>

View File

@ -20,6 +20,7 @@
##############################################################################
import time
from psycopg2 import OperationalError
from openerp import SUPERUSER_ID
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):
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:
#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
#will fetch all the ids again)
procurement = self.browse(cr, uid, procurement_id, context=context)
if procurement.state not in ("running", "done"):
if self._assign(cr, uid, procurement, context=context):
procurement.refresh()
res = self._run(cr, uid, procurement, context=context or {})
if res:
self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context)
try:
if self._assign(cr, uid, procurement, context=context):
procurement.refresh()
res = self._run(cr, uid, procurement, context=context or {})
if res:
self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context)
else:
self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context)
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)
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)
if autocommit:
cr.commit()
except OperationalError:
if autocommit:
cr.rollback()
continue
else:
raise
return True
def check(self, cr, uid, ids, context=None):
def check(self, cr, uid, ids, autocommit=False, context=None):
done_ids = []
for procurement in self.browse(cr, uid, ids, context=context):
result = self._check(cr, uid, procurement, context=context)
if result:
done_ids.append(procurement.id)
try:
result = self._check(cr, uid, procurement, context=context)
if result:
done_ids.append(procurement.id)
if autocommit:
cr.commit()
except OperationalError:
if autocommit:
cr.rollback()
continue
else:
raise
if done_ids:
self.write(cr, uid, done_ids, {'state': 'done'}, context=context)
return done_ids
@ -291,11 +310,14 @@ class procurement_order(osv.osv):
dom = [('state', '=', 'confirmed')]
if company_id:
dom += [('company_id', '=', company_id)]
prev_ids = []
while True:
ids = self.search(cr, SUPERUSER_ID, dom, context=context)
if not ids:
if not ids or prev_ids == ids:
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:
cr.commit()
@ -304,12 +326,14 @@ class procurement_order(osv.osv):
dom = [('state', '=', 'running')]
if company_id:
dom += [('company_id', '=', company_id)]
prev_ids = []
while True:
ids = self.search(cr, SUPERUSER_ID, dom, offset=offset, context=context)
if not ids:
if not ids or prev_ids == ids:
break
done = self.check(cr, SUPERUSER_ID, ids, context=context)
offset += len(ids) - len(done)
else:
prev_ids = ids
self.check(cr, SUPERUSER_ID, ids, autocommit=use_new_cursor, context=context)
if use_new_cursor:
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 dateutil.relativedelta import relativedelta
from datetime import datetime
from psycopg2 import OperationalError
import openerp
class procurement_group(osv.osv):
@ -204,8 +205,8 @@ class procurement_order(osv.osv):
return True
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
def run(self, cr, uid, ids, context=None):
res = super(procurement_order, self).run(cr, uid, ids, context=context)
def run(self, cr, uid, ids, autocommit=False, context=None):
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
#(we do that in batch because it fasts the picking assignation and the picking state computation)
move_to_confirm_ids = []
@ -335,36 +336,51 @@ class procurement_order(osv.osv):
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
procurement_obj = self.pool.get('procurement.order')
offset = 0
ids = [1]
dom = company_id and [('company_id', '=', company_id)] or []
while ids:
ids = orderpoint_obj.search(cr, uid, dom, offset=offset, limit=100)
orderpoint_ids = orderpoint_obj.search(cr, uid, dom)
prev_ids = []
while orderpoint_ids:
ids = orderpoint_ids[:100]
del orderpoint_ids[:100]
for op in orderpoint_obj.browse(cr, uid, ids, context=context):
prods = self._product_virtual_get(cr, uid, op)
if prods is None:
continue
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:
try:
prods = self._product_virtual_get(cr, uid, op)
if prods is None:
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:
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])
offset += len(ids)
if qty <= 0:
continue
qty -= orderpoint_obj.subtract_procurements(cr, uid, op, context=context)
if qty > 0:
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:
cr.commit()
if prev_ids == ids:
break
else:
prev_ids = ids
if use_new_cursor:
cr.commit()
cr.close()

View File

@ -1418,16 +1418,18 @@ class ExportFormat(object):
raise NotImplementedError()
def base(self, data, token):
params = simplejson.loads(data)
model, fields, ids, domain, import_compat = \
operator.itemgetter('model', 'fields', 'ids', 'domain',
'import_compat')(
simplejson.loads(data))
params)
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)
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:
columns_headers = field_names

View File

@ -406,6 +406,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
fields: exported_fields,
ids: this.ids_to_export,
domain: this.domain,
context: this.dataset.context,
import_compat: !!this.$el.find("#import_compat").val(),
})},
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 () {
var self = this;
this.autocomplete = new instance.web.search.AutoComplete(this, {
source: this.proxy('complete_global_search'),
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;
}
} else if (self.dataset.index >= self.records.length) {
self.dataset.index = 0;
self.dataset.index = self.records.length ? 0 : null;
}
self.compute_aggregates();

View File

@ -423,14 +423,15 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
attrs.value = [attrs.value];
}
attrs.value = _.range(grouped_on.length).map(function (i) {
var grp = grouped_on[i],
field = self.fields[grp];
if (attrs.value[i] === false) {
return _t('Undefined');
} else if (attrs.value[i] instanceof Array) {
return attrs.value[i][1];
}else if (grouped_on && self.fields[grouped_on].type === 'selection'){
var selection = self.fields[grouped_on].selection;
var value_lookup = _.where(selection, {0:attrs.value[i]});
return value_lookup ? value_lookup[0][1] : _t('Undefined');
} else if (field && field.type === 'selection') {
var selected = _.where(field.selection, {0: attrs.value[i]})[0];
return selected ? selected[1] : 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);
if (!_.isEmpty(self.dataset.ids) && (self.dataset.index === null || self.dataset.index >= self.dataset.ids.length)) {
self.dataset.index = 0;
} else if (_.isEmpty(self.dataset.ids)){
self.dataset.index = null;
}
self.do_add_groups([kgroup]).done(function() {
if (_.isEmpty(records)) {

View File

@ -131,8 +131,8 @@
<!-- 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>
<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/"
style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe>
<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;" scrolling="no"></iframe>
</ul>
</xpath>
</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)
# pager
url = '/customers/'
if country_id:
url += 'country/%s' % country_id
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
)

View File

@ -84,8 +84,8 @@
<!-- 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>
<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/"
style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe>
<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;" scrolling="no"></iframe>
</ul>
</xpath>
</template>

View File

@ -90,9 +90,12 @@ class website_event(http.Controller):
if searches["type"] != 'all':
current_type = type_obj.browse(cr, uid, int(searches['type']), context=context)
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)
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):
domain = [('state', "in", ['draft','confirm','done'])]

View File

@ -57,6 +57,7 @@
<div itemscope="itemscope" itemtype="http://schema.org/Event" class="media-body">
<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>
<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>
</h4>
<div>
@ -179,7 +180,13 @@
<ul class="nav nav-pills nav-stacked mt32">
<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 ''">
<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>
</a>
</li>

View File

@ -29,19 +29,18 @@
<h4>Choose your Delivery Method</h4>
<ul class="list-unstyled">
<li t-foreach="deliveries" t-as="delivery">
<label>
<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-disabled="delivery.available and '0' or '1'"/>
<span t-field="delivery.name"/>
<t t-if="delivery.available">
<t t-if="delivery.available">
<label>
<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"/>
<span t-field="delivery.name"/>
<span class="badge" t-field="delivery.price"
t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
</t>
</label>
</label>
</t>
</li>
</ul>
</div>

View File

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

View File

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

View File

@ -3168,6 +3168,11 @@ class BaseModel(object):
env = self.env
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.
# 'tables' holds the list of tables necessary for the SELECT, including
# 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)
user = registry['res.users'].browse(cr, SUPERUSER_ID, uid)
tz_name = user.tz
utc_timestamp = pytz.utc.localize(timestamp, is_dst=False) # UTC = no DST
if tz_name:
try:
utc = pytz.utc
context_tz = pytz.timezone(tz_name)
utc_timestamp = utc.localize(timestamp, is_dst=False) # UTC = no DST
return utc_timestamp.astimezone(context_tz)
except Exception:
_logger.debug("failed to compute context/client-specific timestamp, "
"using the UTC value",
exc_info=True)
return timestamp
return utc_timestamp
class binary(_column):
_type = 'binary'