[MERGE] forward port of branch saas-4 up to 0a1e4a0

This commit is contained in:
Denis Ledoux 2014-08-08 17:27:29 +02:00
commit 7c647ec876
32 changed files with 198 additions and 85 deletions

View File

@ -174,6 +174,8 @@ class account_invoice(osv.osv):
lines = []
if invoice.move_id:
for m in invoice.move_id.line_id:
if m.account_id != invoice.account_id:
continue
temp_lines = []
if m.reconcile_id:
temp_lines = map(lambda x: x.id, m.reconcile_id.line_id)

View File

@ -23,7 +23,7 @@
<record id="email_template_edi_invoice" model="email.template">
<field name="name">Invoice - Send by Email</field>
<field name="email_from">${(object.user_id.email or object.company_id.email or 'noreply@localhost')|safe}</field>
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a'})</field>
<field name="subject">${object.company_id.name|safe} Invoice (Ref ${object.number or 'n/a'})</field>
<field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="account.model_account_invoice"/>
<field name="auto_delete" eval="True"/>

View File

@ -32,7 +32,7 @@
<separator/>
<filter icon="terp-dolar" string="Invoice" domain="['|', ('type','=','out_invoice'),('type','=','in_invoice')]" help="Customer And Supplier Invoices"/>
<filter icon="terp-dolar_ok!" string="Refund" domain="['|', ('type','=','out_refund'),('type','=','in_refund')]" help="Customer And Supplier Refunds"/>
<field name="partner_id"/>
<field name="partner_id" operator="child_of"/>
<field name="user_id" />
<field name="categ_id" filter_domain="[('categ_id', 'child_of', self)]"/>
<group expand="1" string="Group By...">

View File

@ -132,7 +132,7 @@ class account_fiscalyear_close(osv.osv_memory):
FROM account_account a
LEFT JOIN account_account_type t ON (a.user_type = t.id)
WHERE a.active
AND a.type != 'view'
AND a.type not in ('view', 'consolidation')
AND a.company_id = %s
AND t.close_method = %s''', (company_id, 'unreconciled', ))
account_ids = map(lambda x: x[0], cr.fetchall())
@ -182,7 +182,7 @@ class account_fiscalyear_close(osv.osv_memory):
FROM account_account a
LEFT JOIN account_account_type t ON (a.user_type = t.id)
WHERE a.active
AND a.type != 'view'
AND a.type not in ('view', 'consolidation')
AND a.company_id = %s
AND t.close_method = %s''', (company_id, 'detail', ))
account_ids = map(lambda x: x[0], cr.fetchall())
@ -211,7 +211,7 @@ class account_fiscalyear_close(osv.osv_memory):
FROM account_account a
LEFT JOIN account_account_type t ON (a.user_type = t.id)
WHERE a.active
AND a.type != 'view'
AND a.type not in ('view', 'consolidation')
AND a.company_id = %s
AND t.close_method = %s''', (company_id, 'balance', ))
account_ids = map(lambda x: x[0], cr.fetchall())

View File

@ -210,7 +210,7 @@ class account_analytic_plan_instance(osv.osv):
ana_plan_instance_obj = self.pool.get('account.analytic.plan.instance')
acct_anal_acct = self.pool.get('account.analytic.account')
acct_anal_plan_line_obj = self.pool.get('account.analytic.plan.line')
if context and 'journal_id' in context:
if context and context.get('journal_id'):
journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
pids = ana_plan_instance_obj.search(cr, uid, [('name','=',vals['name']), ('code','=',vals['code']), ('plan_id','<>',False)], context=context)

View File

@ -22,6 +22,7 @@
##############################################################################
from openerp.osv import osv, fields
from openerp.tools.float_utils import float_round as round
class account_invoice_line(osv.osv):
_inherit = "account.invoice.line"
@ -36,11 +37,12 @@ class account_invoice_line(osv.osv):
company_currency = inv.company_id.currency_id.id
def get_price(cr, uid, inv, company_currency, i_line, price_unit):
cur_obj = self.pool.get('res.currency')
decimal_precision = self.pool.get('decimal.precision')
if inv.currency_id.id != company_currency:
price = cur_obj.compute(cr, uid, company_currency, inv.currency_id.id, price_unit * i_line.quantity, context={'date': inv.date_invoice})
else:
price = price_unit * i_line.quantity
return price
return round(price, decimal_precision.precision_get(cr, uid, 'Account'))
if inv.type in ('out_invoice','out_refund'):
for i_line in inv.invoice_line:
@ -118,6 +120,8 @@ class account_invoice_line(osv.osv):
fpos = i_line.invoice_id.fiscal_position or False
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
diff_res = []
decimal_precision = self.pool.get('decimal.precision')
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']:
@ -132,14 +136,14 @@ class account_invoice_line(osv.osv):
if valuation_stock_move:
valuation_price_unit = stock_move_obj.browse(cr, uid, valuation_stock_move[0], context=context).price_unit
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
price_diff = i_line.price_unit - valuation_price_unit
line.update({'price': valuation_price_unit * line['quantity']})
price_diff = round(i_line.price_unit - valuation_price_unit, account_prec)
line.update({'price': round(valuation_price_unit * line['quantity'], account_prec)})
diff_res.append({
'type': 'src',
'name': i_line.name[:64],
'price_unit': price_diff,
'quantity': line['quantity'],
'price': price_diff * line['quantity'],
'price': round(price_diff * line['quantity'], account_prec),
'account_id': acc,
'product_id': line['product_id'],
'uos_id': line['uos_id'],

View File

@ -1039,7 +1039,8 @@ class account_voucher(osv.osv):
'period_id': voucher.period_id.id,
'partner_id': voucher.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': company_currency <> current_currency and sign * voucher.amount or 0.0,
'amount_currency': (sign * abs(voucher.amount) # amount < 0 for refunds
if company_currency != current_currency else 0.0),
'date': voucher.date,
'date_maturity': voucher.date_due
}
@ -1201,7 +1202,7 @@ class account_voucher(osv.osv):
if line.amount == line.amount_unreconciled:
if not line.move_line_id:
raise osv.except_osv(_('Wrong voucher line'),_("The invoice you are willing to pay is not valid anymore."))
sign = voucher.type in ('payment', 'purchase') and -1 or 1
sign = line.type =='dr' and -1 or 1
currency_rate_difference = sign * (line.move_line_id.amount_residual - amount)
else:
currency_rate_difference = 0.0
@ -1259,8 +1260,7 @@ class account_voucher(osv.osv):
# otherwise we use the rates of the system
amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
if line.amount == line.amount_unreconciled:
sign = voucher.type in ('payment', 'purchase') and -1 or 1
foreign_currency_diff = sign * line.move_line_id.amount_residual_currency + amount_currency
foreign_currency_diff = line.move_line_id.amount_residual_currency - abs(amount_currency)
move_line['amount_currency'] = amount_currency
voucher_line = move_line_obj.create(cr, uid, move_line)

View File

@ -302,7 +302,7 @@ class account_analytic_account(osv.osv):
dom = []
for name2 in name.split('/'):
name = name2.strip()
account_ids = self.search(cr, uid, dom + [('name', 'ilike', name)] + args, limit=limit, context=context)
account_ids = self.search(cr, uid, dom + [('name', operator, name)] + args, limit=limit, context=context)
if not account_ids: break
dom = [('parent_id','in',account_ids)]
else:

View File

@ -903,6 +903,15 @@ class calendar_event(osv.Model):
'partner_ids': fields.many2many('res.partner', 'calendar_event_res_partner_rel', string='Attendees', states={'done': [('readonly', True)]}),
'alarm_ids': fields.many2many('calendar.alarm', 'calendar_alarm_calendar_event_rel', string='Reminders', ondelete="restrict"),
}
def _get_default_partners(self, cr, uid, ctx=None):
ret = [self.pool['res.users'].browse(cr, uid, uid, context=ctx).partner_id.id]
active_id = ctx.get('active_id')
if ctx.get('active_model') == 'res.partner' and active_id:
if active_id not in ret:
ret.append(active_id)
return ret
_defaults = {
'end_type': 'count',
'count': 1,
@ -915,7 +924,7 @@ class calendar_event(osv.Model):
'interval': 1,
'active': 1,
'user_id': lambda self, cr, uid, ctx: uid,
'partner_ids': lambda self, cr, uid, ctx: [self.pool['res.users'].browse(cr, uid, [uid], context=ctx)[0].partner_id.id]
'partner_ids': _get_default_partners,
}
def _check_closing_date(self, cr, uid, ids, context=None):

View File

@ -41,7 +41,7 @@
<h1>
<field name="name"/>
</h1>
<label for="partner_ids" class="oe_edit_only"/>
<label for="partner_ids" string="Attendees" class="oe_edit_only"/>
<h2>
<field name="partner_ids" widget="many2manyattendee"
context="{'force_email':True}"

View File

@ -6,6 +6,7 @@ import htmlentitydefs
import itertools
import logging
import operator
import psycopg2
import re
from ast import literal_eval
from openerp.tools import mute_logger
@ -186,28 +187,29 @@ class MergePartnerAutomatic(osv.TransientModel):
for partner_id in partner_ids:
cr.execute(query, (dst_partner.id, partner_id, dst_partner.id))
else:
cr.execute("SAVEPOINT recursive_partner_savepoint")
try:
query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic
cr.execute(query, (dst_partner.id, partner_ids,))
with mute_logger('openerp.sql_db'), cr.savepoint():
query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic
cr.execute(query, (dst_partner.id, partner_ids,))
if column == proxy._parent_name and table == 'res_partner':
query = """
WITH RECURSIVE cycle(id, parent_id) AS (
SELECT id, parent_id FROM res_partner
UNION
SELECT cycle.id, res_partner.parent_id
FROM res_partner, cycle
WHERE res_partner.id = cycle.parent_id AND
cycle.id != cycle.parent_id
)
SELECT id FROM cycle WHERE id = parent_id AND id = %s
"""
cr.execute(query, (dst_partner.id,))
if cr.fetchall():
cr.execute("ROLLBACK TO SAVEPOINT recursive_partner_savepoint")
finally:
cr.execute("RELEASE SAVEPOINT recursive_partner_savepoint")
if column == proxy._parent_name and table == 'res_partner':
query = """
WITH RECURSIVE cycle(id, parent_id) AS (
SELECT id, parent_id FROM res_partner
UNION
SELECT cycle.id, res_partner.parent_id
FROM res_partner, cycle
WHERE res_partner.id = cycle.parent_id AND
cycle.id != cycle.parent_id
)
SELECT id FROM cycle WHERE id = parent_id AND id = %s
"""
cr.execute(query, (dst_partner.id,))
except psycopg2.Error:
# updating fails, most likely due to a violated unique constraint
# keeping record with nonexistent partner_id is useless, better delete it
query = 'DELETE FROM %(table)s WHERE %(column)s = %%s' % query_dic
cr.execute(query, (partner_id,))
def _update_reference_fields(self, cr, uid, src_partners, dst_partner, context=None):
_logger.debug('_update_reference_fields for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners)))

View File

@ -124,7 +124,7 @@
<group colspan="2" col="2" groups="base.group_user">
<separator colspan="2" string="Responsibilities"/>
<field name="user_fault"/>
<field name="categ_id" widget="selection"
<field name="categ_id" options="{'no_create': True, 'no_open': True}"
domain="[('object_id.model', '=', 'crm.claim')]"/>
<field name="ref"/>
</group>

View File

@ -34,9 +34,34 @@ from openerp import tools
from openerp.tools.translate import _
from urllib import urlencode, quote as quote
_logger = logging.getLogger(__name__)
def format_tz(pool, cr, uid, dt, tz=False, format=False, context=None):
context = dict(context or {})
if tz:
context['tz'] = tz or pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz'] or "UTC"
timestamp = datetime.datetime.strptime(dt, tools.DEFAULT_SERVER_DATETIME_FORMAT)
ts = fields.datetime.context_timestamp(cr, uid, timestamp, context)
if format:
return ts.strftime(format)
else:
lang = context.get("lang")
lang_params = {}
if lang:
res_lang = pool.get('res.lang')
ids = res_lang.search(cr, uid, [("code", "=", lang)])
if ids:
lang_params = res_lang.read(cr, uid, ids[0], ["date_format", "time_format"])
format_date = lang_params.get("date_format", '%B-%d-%Y')
format_time = lang_params.get("time_format", '%I-%M %p')
fdate = ts.strftime(format_date)
ftime = ts.strftime(format_time)
return "%s %s (%s)" % (fdate, ftime, tz)
try:
# We use a jinja2 sandboxed environment to render mako templates.
# Note that the rendering does not cover all the mako syntax, in particular
@ -164,6 +189,7 @@ class email_template(osv.osv):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
records = self.pool[model].browse(cr, uid, res_ids, context=context) or [None]
variables = {
'format_tz': lambda dt, tz=False, format=False: format_tz(self.pool, cr, uid, dt, tz, format, context),
'user': user,
'ctx': context, # context kw would clash with mako internals
}

View File

@ -640,7 +640,7 @@
<field name="style_overwrite" eval="2"/>
</record>
<record id="account_financial_report_bnficepertedelexcerciceavantimpts1" model="account.financial.report">
<field name="name">Bénéfice (Perte) de l'excercice avant impôts</field>
<field name="name">Bénéfice (Perte) de l'exercice avant impôts</field>
<field eval="8" name="sequence"/>
<field name="parent_id" ref="account_financial_report_belgiumpl0"/>
<field name="display_detail">no_detail</field>
@ -674,7 +674,7 @@
<field name="style_overwrite" eval="2"/>
</record>
<record id="account_financial_report_bnficepertedelexcercice1" model="account.financial.report">
<field name="name">Bénéfice (Perte) de l'excercice</field>
<field name="name">Bénéfice (Perte) de l'exercice</field>
<field eval="12" name="sequence"/>
<field name="parent_id" ref="account_financial_report_belgiumpl0"/>
<field name="display_detail">no_detail</field>

View File

@ -48,6 +48,7 @@ class mail_followers(osv.Model):
help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."),
}
_sql_constraints = [('mail_followers_res_partner_res_model_id_uniq','unique(res_model,res_id,partner_id)','Error, a partner cannot follow twice the same object.')]
class mail_notification(osv.Model):
""" Class holding notifications pushed to partners. Followers and partners

View File

@ -50,10 +50,11 @@
<t t-if="!widget.options.view_mailbox">
<div class="field_text oe_compact oe_compact_record">
<a class="oe_compose_post" t-if="widget.options.compose_placeholder"><t t-raw="widget.options.compose_placeholder"/></a>
<a class="oe_compose_post" t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox">Send a message</a>
<a class="oe_compose_post" t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox"
title="Send a message to all followers of the document">Send a message</a>
<t t-if="widget.options.display_log_button">
<span class="oe_grey oe_sep_word">or</span>
<a class="oe_compose_log">Log an internal note</a>
<a class="oe_compose_log" title="Log a note for this document. No notification will be sent">Log an internal note</a>
</t>
</div>
</t>

View File

@ -40,13 +40,21 @@ class PaypalController(http.Controller):
Once data is validated, process it. """
res = False
new_post = dict(post, cmd='_notify-validate')
urequest = urllib2.Request("https://www.sandbox.paypal.com/cgi-bin/webscr", werkzeug.url_encode(new_post))
cr, uid, context = request.cr, request.uid, request.context
reference = post.get('item_number')
tx = None
if reference:
tx_ids = request.registry['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
if tx_ids:
tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
paypal_urls = request.registry['payment.acquirer']._get_paypal_urls(cr, uid, tx and tx.acquirer_id and tx.acquirer_id.env or 'prod', context=context)
validate_url = paypal_urls['paypal_form_url']
urequest = urllib2.Request(validate_url, werkzeug.url_encode(new_post))
uopen = urllib2.urlopen(urequest)
resp = uopen.read()
if resp == 'VERIFIED':
_logger.info('Paypal: validated data')
cr, uid, context = request.cr, SUPERUSER_ID, request.context
res = request.registry['payment.transaction'].form_feedback(cr, uid, post, 'paypal', context=context)
res = request.registry['payment.transaction'].form_feedback(cr, SUPERUSER_ID, post, 'paypal', context=context)
elif resp == 'INVALID':
_logger.warning('Paypal: answered INVALID on data verification')
else:

View File

@ -60,6 +60,7 @@
</div>
<field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator"/>
</group>
<div class="oe_clear"/>
</page>
<page string="Payments">
<field name="statement_ids" colspan="4" nolabel="1">

View File

@ -777,7 +777,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.user.name"/><br />
User: <t t-esc="widget.pos.cashier.name"/><br />
<br />
<t t-if="widget.pos.config.receipt_header">
<div style='text-align:center'>

View File

@ -19,3 +19,4 @@
#
##############################################################################
import portal_claim

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import SUPERUSER_ID
from openerp.osv import osv
class crm_claim(osv.osv):
_inherit = "crm.claim"
def _get_default_partner_id(self, cr, uid, context=None):
""" Gives default partner_id """
if context is None:
context = {}
if context.get('portal'):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
# Special case for portal users, as they are not allowed to call name_get on res.partner
# We save this call for the web client by returning it in default get
return self.pool['res.partner'].name_get(cr, SUPERUSER_ID, [user.partner_id.id], context=context)[0]
return False
_defaults = {
'partner_id': lambda s, cr, uid, c: s._get_default_partner_id(cr, uid, c),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,7 +7,7 @@
<record id="email_template_edi_sale" model="email.template">
<field name="name">Sales Order - Send by Email (Portal)</field>
<field name="email_from">${(object.user_id.email or '')|safe}</field>
<field name="subject">${object.company_id.name} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
<field name="subject">${object.company_id.name|safe} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
<field name="partner_to">${object.partner_invoice_id.id}</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="auto_delete" eval="True"/>
@ -97,7 +97,7 @@
<record id="email_template_edi_invoice" model="email.template">
<field name="name">Invoice - Send by Email (Portal)</field>
<field name="email_from">${(object.user_id.email or object.company_id.email or 'noreply@localhost')|safe}</field>
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field>
<field name="subject">${object.company_id.name|safe} Invoice (Ref ${object.number or 'n/a' })</field>
<field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="account.model_account_invoice"/>
<field name="auto_delete" eval="True"/>

View File

@ -19,8 +19,8 @@
<!--Email template -->
<record id="email_template_edi_purchase" model="email.template">
<field name="name">RFQ - Send by Email</field>
<field name="email_from">${object.validator.email or ''}</field>
<field name="subject">${object.company_id.name} Order (Ref ${object.name or 'n/a' })</field>
<field name="email_from">${(object.validator.email or '')|safe}</field>
<field name="subject">${object.company_id.name|safe} Order (Ref ${object.name or 'n/a' })</field>
<field name="partner_to">${object.partner_id.id}</field>
<field name="model_id" ref="purchase.model_purchase_order"/>
<field name="auto_delete" eval="True"/>

View File

@ -21,7 +21,7 @@
<record id="email_template_edi_sale" model="email.template">
<field name="name">Sales Order - Send by Email</field>
<field name="email_from">${(object.user_id.email or '')|safe}</field>
<field name="subject">${object.company_id.name} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
<field name="subject">${object.company_id.name|safe} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
<field name="partner_to">${object.partner_invoice_id.id}</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="auto_delete" eval="True"/>

View File

@ -1959,13 +1959,12 @@ class stock_move(osv.osv):
product = self.pool.get('product.product').browse(cr, uid, [prod_id], context=ctx)[0]
uos_id = product.uos_id and product.uos_id.id or False
result = {
'name': product.partner_ref,
'product_uom': product.uom_id.id,
'product_uos': uos_id,
'product_uom_qty': 1.00,
'product_uos_qty': self.pool.get('stock.move').onchange_quantity(cr, uid, ids, prod_id, 1.00, product.uom_id.id, uos_id)['value']['product_uos_qty'],
}
if not ids:
result['name'] = product.partner_ref
if loc_id:
result['location_id'] = loc_id
if loc_dest_id:

View File

@ -28,7 +28,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
// ----------------------------------------------------------------------
// this.measures: list of measure [measure], measure = {field: _, string: _, type: _}
// this.rows.groupby, this.cols.groupby : list of groupbys used for describing rows (...),
// a groupby is also {field:_, string:_, type:_}
// a groupby is also {field:_, string:_, type:_}
// If its type is date/datetime, field can have the corresponding interval in its description,
// for example 'create_date:week'.
set_measures: function (measures) {
@ -65,7 +65,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
}
var row_gb_changed = !_.isEqual(row_groupby, this.rows.groupby),
col_gb_changed = !_.isEqual(col_groupby, this.cols.groupby);
this.domain = domain;
this.rows.groupby = row_groupby;
this.cols.groupby = col_groupby;
@ -80,7 +80,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
// Cells manipulation methods
// ----------------------------------------------------------------------
// cells are objects {x:_, y:_, values:_} where x < y and values is an array
// of values (one for each measure). The condition x < y might look
// of values (one for each measure). The condition x < y might look
// unnecessary, but it makes the rest of the code simpler: headers
// don't krow if they are rows or cols, they just know their id, so
// it is useful that a call get_values(id1, id2) is the same as get_values(id2, id1)
@ -103,9 +103,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
// ----------------------------------------------------------------------
// Headers/Rows/Cols manipulation methods
// ----------------------------------------------------------------------
// this.rows.headers, this.cols.headers = [header] describe the tree structure
// this.rows.headers, this.cols.headers = [header] describe the tree structure
// of rows/cols. Headers are objects
// {
// {
// id:_, (unique id obviously)
// path: [...], (array of all parents title, with its own title at the end)
// title:_, (name of the row/col)
@ -150,12 +150,12 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
get_rows_leaves: function () {
return _.where(this.rows.headers, {expanded:false});
},
// return all non expanded cols
get_cols_leaves: function () {
return _.where(this.cols.headers, {expanded:false});
},
get_ancestors: function (header) {
var self = this;
if (!header.children) return [];
@ -181,7 +181,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
},
main_row: function () { return this.rows.headers[0]; },
main_col: function () { return this.cols.headers[0]; },
// ----------------------------------------------------------------------
@ -255,7 +255,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
// Data updating methods
// ----------------------------------------------------------------------
// update_data will try to preserve the expand/not expanded status of each
// column/row. If you want to expand all, then set this.cols.headers/this.rows.headers
// column/row. If you want to expand all, then set this.cols.headers/this.rows.headers
// to null before calling update_data.
update_data: function () {
var self = this;
@ -289,7 +289,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
data_pts.forEach(function (data_pt) {
var row_value = (prefix || []).concat(data_pt.attributes.value.slice(0,index));
var col_value = data_pt.attributes.value.slice(index);
if (expand && !_.find(col_headers, function (hdr) {return self.isEqual(col_value, hdr.path);})) {
return;
}
@ -427,6 +427,10 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
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');
}
return attrs.value[i];
});
@ -445,8 +449,8 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({
isEqual: function (path1, path2) {
if (path1.length !== path2.length) { return false; }
for (var i = 0; i < path1.length; i++) {
if (path1[i] !== path2[i]) {
return false;
if (path1[i] !== path2[i]) {
return false;
}
}
return true;

View File

@ -300,6 +300,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
self.do_clear_groups();
self.dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit }).done(function(records) {
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;
}
self.do_add_groups([kgroup]).done(function() {
if (_.isEmpty(records)) {
self.no_result();

View File

@ -217,8 +217,13 @@ class ModelConverter(ir.ir_http.ModelConverter):
def to_python(self, value):
m = re.match(self.regex, value)
_uid = RequestUID(value=value, match=m, converter=self)
record_id = int(m.group(2))
if record_id < 0:
# limited support for negative IDs due to our slug pattern, assume abs() if not found
if not request.registry[self.model].exists(request.cr, _uid, [record_id]):
record_id = abs(record_id)
return request.registry[self.model].browse(
request.cr, _uid, int(m.group(2)), context=request.context)
request.cr, _uid, record_id, context=request.context)
def generate(self, cr, uid, query=None, args=None, context=None):
obj = request.registry[self.model]

View File

@ -93,15 +93,15 @@
<t t-call-assets="website.assets_frontend"/>
<t t-raw="head or ''" name='layout_head'/>
<t t-if="website.google_analytics_key">
<script>
<t t-if="website.google_analytics_key">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','_gaw');
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
_gaw('create',_.str.trim('<t t-esc="website.google_analytics_key"/>'));
_gaw('send','pageview');
ga('create',_.str.trim('<t t-esc="website.google_analytics_key"/>'));
ga('send','pageview');
</script>
</t>
</head>
@ -676,7 +676,6 @@
<div class="oe_structure">
<h1 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h1>
</div>
<div class="container" t-if="views">
<div class="alert alert-danger" t-if="qweb_exception and editable">
<h4>Template fallback</h4>

View File

@ -64,11 +64,14 @@ class sale_quote_line(osv.osv):
def on_change_product_id(self, cr, uid, ids, product, context=None):
vals = {}
product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
name = product_obj.name
if product_obj.description_sale:
name += '\n' + product_obj.description_sale
vals.update({
'price_unit': product_obj.list_price,
'product_uom_id': product_obj.uom_id.id,
'website_description': product_obj.website_description,
'name': product_obj.name,
'name': name,
})
return {'value': vals}

View File

@ -267,7 +267,9 @@ class rml_parse(object):
elif (hasattr(obj, '_field') and\
isinstance(obj._field, (float_field, function_field)) and\
obj._field.digits):
d = obj._field.digits[1] or DEFAULT_DIGITS
d = obj._field.digits[1]
if not d and d is not 0:
d = DEFAULT_DIGITS
return d
def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False, dp=False, currency_obj=False):

View File

@ -446,16 +446,15 @@ class YamlInterpreter(object):
args = map(lambda x: eval(x, ctx), match.group(2).split(','))
result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args)
for key, val in (result or {}).get('value', {}).items():
assert key in fg, (
"The field %r returned from the onchange call %r "
"does not exist in the source view %r (of object "
"%r). This field will be ignored (and thus not "
"populated) when clients saves the new record" % (
key, match.group(1), view_info.get('name', '?'), model._name
))
if key not in fields:
# do not shadow values explicitly set in yaml.
record_dict[key] = process_val(key, val)
if key in fg:
if key not in fields:
# do not shadow values explicitly set in yaml.
record_dict[key] = process_val(key, val)
else:
_logger.warning("The returning field '%s' from your on_change call '%s'"
" does not exist either on the object '%s', either in"
" the view '%s'",
key, match.group(1), model._name, view_info['name'])
else:
nodes = list(el) + nodes
else: