diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index f081b7f0c26..4e2e041efea 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -182,8 +182,10 @@
+
+ on_change="onchange_journal_id(journal_id)" options="{'no_create': True}"
+ attrs="{'readonly':[('internal_number','!=',False)]}"/>
@@ -328,8 +330,10 @@
+
+ on_change="onchange_journal_id(journal_id)" options="{'no_create': True}"
+ attrs="{'readonly':[('internal_number','!=',False)]}"/>
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
index 820c29c5e58..56132b3ab46 100644
--- a/addons/account/account_move_line.py
+++ b/addons/account/account_move_line.py
@@ -451,7 +451,7 @@ class account_move_line(osv.osv):
'debit': fields.float('Debit', digits_compute=dp.get_precision('Account')),
'credit': fields.float('Credit', digits_compute=dp.get_precision('Account')),
'account_id': fields.many2one('account.account', 'Account', required=True, ondelete="cascade", domain=[('type','<>','view'), ('type', '<>', 'closed')], select=2),
- 'move_id': fields.many2one('account.move', 'Journal Entry', ondelete="cascade", help="The move of this entry line.", select=2, required=True),
+ 'move_id': fields.many2one('account.move', 'Journal Entry', ondelete="cascade", help="The move of this entry line.", select=2, required=True, auto_join=True),
'narration': fields.related('move_id','narration', type='text', relation='account.move', string='Internal Note'),
'ref': fields.related('move_id', 'ref', string='Reference', type='char', store=True),
'statement_id': fields.many2one('account.bank.statement', 'Statement', help="The bank statement used for bank reconciliation", select=1, copy=False),
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index 23fbeb598b8..84a6a07332e 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -309,6 +309,7 @@ class res_partner(osv.osv):
('reconcile_id', '=', False),
('state', '!=', 'draft'),
('company_id', '=', company_id),
+ ('date_maturity', '<=', fields.date.context_today(self,cr,uid)),
], context=context):
raise osv.except_osv(_('Error!'),_("The partner does not have any accounting entries to print in the overdue report for the current company."))
self.message_post(cr, uid, [ids[0]], body=_('Printed overdue payments report'), context=context)
diff --git a/addons/account_followup/report/account_followup_print.py b/addons/account_followup/report/account_followup_print.py
index 0c9d9b8c490..292b5e044ee 100644
--- a/addons/account_followup/report/account_followup_print.py
+++ b/addons/account_followup/report/account_followup_print.py
@@ -21,7 +21,7 @@
import time
from collections import defaultdict
-from openerp.osv import osv
+from openerp.osv import osv, fields
from openerp.report import report_sxw
@@ -55,6 +55,7 @@ class report_rappel(report_sxw.rml_parse):
('reconcile_id', '=', False),
('state', '!=', 'draft'),
('company_id', '=', company_id),
+ ('date_maturity', '<=', fields.date.context_today(self,self.cr,self.uid)),
])
# lines_per_currency = {currency: [line data, ...], ...}
diff --git a/addons/analytic/analytic_view.xml b/addons/analytic/analytic_view.xml
index 7b1b16037cf..ba28acd7cd5 100644
--- a/addons/analytic/analytic_view.xml
+++ b/addons/analytic/analytic_view.xml
@@ -29,7 +29,7 @@
-
+
diff --git a/addons/board/board.py b/addons/board/board.py
index 7f867fa1b11..b6b41bffe62 100644
--- a/addons/board/board.py
+++ b/addons/board/board.py
@@ -23,7 +23,7 @@
from operator import itemgetter
from textwrap import dedent
-from openerp import tools
+from openerp import tools, SUPERUSER_ID
from openerp.osv import fields, osv
class board_board(osv.osv):
@@ -143,7 +143,7 @@ class board_create(osv.osv_memory):
''')
}, context=context)
- menu_id = self.pool.get('ir.ui.menu').create(cr, uid, {
+ menu_id = self.pool.get('ir.ui.menu').create(cr, SUPERUSER_ID, {
'name': this.name,
'parent_id': this.menu_parent_id.id,
'action': 'ir.actions.act_window,%s' % (action_id,)
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index d142b4aa403..7d8f908e391 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -313,6 +313,7 @@ class crm_lead(format_address, osv.osv):
values = {
'partner_name': partner.parent_id.name if partner.parent_id else partner.name,
'contact_name': partner.name if partner.parent_id else False,
+ 'title': partner.title and partner.title.id or False,
'street': partner.street,
'street2': partner.street2,
'city': partner.city,
@@ -323,6 +324,7 @@ class crm_lead(format_address, osv.osv):
'mobile': partner.mobile,
'fax': partner.fax,
'zip': partner.zip,
+ 'function': partner.function,
}
return {'value': values}
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index d2d0d0a0533..71315c2fd90 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -559,12 +559,13 @@ class hr_timesheet_sheet_sheet_day(osv.osv):
MAX(id) as id,
name,
sheet_id,
+ timezone,
SUM(total_timesheet) as total_timesheet,
- CASE WHEN SUM(total_attendance) < 0
+ CASE WHEN SUM(orphan_attendances) != 0
THEN (SUM(total_attendance) +
CASE WHEN current_date <> name
THEN 1440
- ELSE (EXTRACT(hour FROM current_time AT TIME ZONE 'UTC') * 60) + EXTRACT(minute FROM current_time AT TIME ZONE 'UTC')
+ ELSE (EXTRACT(hour FROM current_time AT TIME ZONE 'UTC' AT TIME ZONE coalesce(timezone, 'UTC')) * 60) + EXTRACT(minute FROM current_time AT TIME ZONE 'UTC' AT TIME ZONE coalesce(timezone, 'UTC'))
END
)
ELSE SUM(total_attendance)
@@ -573,21 +574,25 @@ class hr_timesheet_sheet_sheet_day(osv.osv):
((
select
min(hrt.id) as id,
+ 'UTC' as timezone,
l.date::date as name,
s.id as sheet_id,
sum(l.unit_amount) as total_timesheet,
+ 0 as orphan_attendances,
0.0 as total_attendance
from
hr_analytic_timesheet hrt
JOIN account_analytic_line l ON l.id = hrt.line_id
LEFT JOIN hr_timesheet_sheet_sheet s ON s.id = hrt.sheet_id
- group by l.date::date, s.id
+ group by l.date::date, s.id, timezone
) union (
select
-min(a.id) as id,
+ p.tz as timezone,
(a.name AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC'))::date as name,
s.id as sheet_id,
0.0 as total_timesheet,
+ SUM(CASE WHEN a.action = 'sign_in' THEN -1 ELSE 1 END) as orphan_attendances,
SUM(((EXTRACT(hour FROM (a.name AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC'))) * 60) + EXTRACT(minute FROM (a.name AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC')))) * (CASE WHEN a.action = 'sign_in' THEN -1 ELSE 1 END)) as total_attendance
from
hr_attendance a
@@ -602,9 +607,9 @@ class hr_timesheet_sheet_sheet_day(osv.osv):
LEFT JOIN res_partner p
ON u.partner_id = p.id
WHERE action in ('sign_in', 'sign_out')
- group by (a.name AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC'))::date, s.id
+ group by (a.name AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC'))::date, s.id, timezone
)) AS foo
- GROUP BY name, sheet_id
+ GROUP BY name, sheet_id, timezone
)) AS bar""")
diff --git a/addons/project/project.py b/addons/project/project.py
index 5e9f4b97200..fdf42ccf6be 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -313,7 +313,7 @@ class project(osv.osv):
return True
_constraints = [
- (_check_dates, 'Error! project start-date must be lower then project end-date.', ['date_start', 'date'])
+ (_check_dates, 'Error! project start-date must be lower than project end-date.', ['date_start', 'date'])
]
def set_template(self, cr, uid, ids, context=None):
@@ -836,7 +836,7 @@ class task(osv.osv):
_constraints = [
(_check_recursion, 'Error ! You cannot create recursive tasks.', ['parent_ids']),
- (_check_dates, 'Error ! Task end-date must be greater then task start-date', ['date_start','date_end'])
+ (_check_dates, 'Error ! Task end-date must be greater than task start-date', ['date_start','date_end'])
]
# Override view according to the company definition
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index a3ae7197f12..87afb9bbc69 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -146,6 +146,19 @@ class purchase_order(osv.osv):
limit=1)
return res and res[0] or False
+ def _has_non_stockable_item(self, cr, uid, ids, *args):
+ res = dict.fromkeys(ids, False)
+ for order in self.browse(cr, uid, ids):
+ for order_line in order.order_line:
+ if (
+ not order_line.product_id
+ or
+ order_line.product_id
+ and order_line.product_id.type not in ('product', 'consu')
+ ):
+ res[order.id] = True
+ return res
+
def _get_picking_in(self, cr, uid, context=None):
obj_data = self.pool.get('ir.model.data')
type_obj = self.pool.get('stock.picking.type')
@@ -295,6 +308,7 @@ class purchase_order(osv.osv):
'create_uid': fields.many2one('res.users', 'Responsible'),
'company_id': fields.many2one('res.company', 'Company', required=True, select=1, states={'confirmed': [('readonly', True)], 'approved': [('readonly', True)]}),
'journal_id': fields.many2one('account.journal', 'Journal'),
+ 'has_non_stockable_item': fields.function(_has_non_stockable_item, method=True, type='boolean', string='Contains a non-stockable item'),
'bid_date': fields.date('Bid Received On', readonly=True, help="Date on which the bid was received"),
'bid_validity': fields.date('Bid Valid Until', help="Date on which the bid expired"),
'picking_type_id': fields.many2one('stock.picking.type', 'Deliver To', help="This will determine picking type of incoming shipment", required=True,
@@ -484,6 +498,7 @@ class purchase_order(osv.osv):
action['res_id'] = pick_ids and pick_ids[0] or False
return action
+
def wkf_approve_order(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'approved', 'date_approve': fields.date.context_today(self,cr,uid,context=context)})
return True
@@ -542,6 +557,10 @@ class purchase_order(osv.osv):
for po in self.browse(cr, uid, ids, context=context):
if not po.order_line:
raise osv.except_osv(_('Error!'),_('You cannot confirm a purchase order without any purchase order line.'))
+ if po.invoice_method == 'picking' and po.has_non_stockable_item is True:
+ raise osv.except_osv(
+ _('Error!'),
+ _("You cannot confirm a purchase order with Invoice Control Method 'Based on incoming shipments' that contains non-stockable items."))
for line in po.order_line:
if line.state=='draft':
todo.append(line.id)
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index a7a28c1d334..dd592894ee6 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -299,6 +299,14 @@ class sale_order_line(osv.osv):
res['value'].update({'product_packaging': False})
return res
+ # set product uom in context to get virtual stock in current uom
+ if res.get('value', {}).get('product_uom'):
+ # use the uom changed by super call
+ context.update({'uom': res['value']['product_uom']})
+ elif uom:
+ # fallback on selected
+ context.update({'uom': uom})
+
#update of result obtained in super function
product_obj = product_obj.browse(cr, uid, product, context=context)
res['value'].update({'product_tmpl_id': product_obj.product_tmpl_id.id, 'delay': (product_obj.sale_delay or 0.0)})
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 4de993bee3f..610c02b1426 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -2842,6 +2842,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
this.$textarea = this.$el.find('textarea');
this.auto_sized = false;
this.default_height = this.$textarea.css('height');
+ if (this.default_height === '0px') this.default_height = '90px';
if (this.get("effective_readonly")) {
this.$textarea.attr('disabled', 'disabled');
}
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 646383a09b1..ee934d6a2c9 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -299,21 +299,24 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
this.$pager
.on('click', 'a[data-pager-action]', function () {
var $this = $(this);
- var max_page = Math.floor(self.dataset.size() / self.limit());
+ var max_page_index = Math.ceil(self.dataset.size() / self.limit()) - 1;
switch ($this.data('pager-action')) {
case 'first':
- self.page = 0; break;
+ self.page = 0;
+ break;
case 'last':
- self.page = max_page - 1;
+ self.page = max_page_index;
break;
case 'next':
- self.page += 1; break;
+ self.page += 1;
+ break;
case 'previous':
- self.page -= 1; break;
+ self.page -= 1;
+ break;
}
if (self.page < 0) {
- self.page = max_page;
- } else if (self.page > max_page) {
+ self.page = max_page_index;
+ } else if (self.page > max_page_index) {
self.page = 0;
}
self.reload_content();
diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py
index 1c9703e8e60..77e4190f552 100644
--- a/openerp/addons/base/ir/ir_attachment.py
+++ b/openerp/addons/base/ir/ir_attachment.py
@@ -140,7 +140,9 @@ class ir_attachment(osv.osv):
return fname
def _file_delete(self, cr, uid, fname):
- count = self.search_count(cr, 1, [('store_fname','=',fname)])
+ # using SQL to include files hidden through unlink or due to record rules
+ cr.execute("SELECT COUNT(*) FROM ir_attachment WHERE store_fname = %s", (fname,))
+ count = cr.fetchone()[0]
full_path = self._full_path(cr, uid, fname)
if not count and os.path.exists(full_path):
try:
diff --git a/openerp/addons/base/ir/ir_filters.py b/openerp/addons/base/ir/ir_filters.py
index f179a8169f0..0aa673f9bc5 100644
--- a/openerp/addons/base/ir/ir_filters.py
+++ b/openerp/addons/base/ir/ir_filters.py
@@ -140,13 +140,14 @@ class ir_filters(osv.osv):
]
def _auto_init(self, cr, context=None):
- super(ir_filters, self)._auto_init(cr, context)
+ result = super(ir_filters, self)._auto_init(cr, context)
# Use unique index to implement unique constraint on the lowercase name (not possible using a constraint)
cr.execute("DROP INDEX IF EXISTS ir_filters_name_model_uid_unique_index") # drop old index w/o action
cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_action_index'")
if not cr.fetchone():
cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_action_index" ON ir_filters
(lower(name), model_id, COALESCE(user_id,-1), COALESCE(action_id,-1))""")
+ return result
_columns = {
'name': fields.char('Filter Name', translate=True, required=True),