summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/account/account.py6
-rw-r--r--addons/account/account_invoice_view.xml2
-rw-r--r--addons/account/account_move_line.py4
-rw-r--r--addons/account/project/project_view.xml2
-rw-r--r--addons/account_analytic_analysis/account_analytic_analysis.py46
-rw-r--r--addons/account_analytic_analysis/account_analytic_analysis_cron.xml2
-rw-r--r--addons/account_analytic_analysis/account_analytic_analysis_view.xml6
-rw-r--r--addons/account_analytic_analysis/test/account_analytic_analysis.yml3
-rw-r--r--addons/account_analytic_plans/account_analytic_plans.py13
-rw-r--r--addons/account_anglo_saxon/invoice.py2
-rw-r--r--addons/account_voucher/account_voucher.py19
-rw-r--r--addons/account_voucher/test/sales_payment.yml3
-rw-r--r--addons/base_geolocalize/views/res_partner_view.xml2
-rw-r--r--addons/calendar/calendar.py9
-rw-r--r--addons/crm/crm_lead_view.xml4
-rw-r--r--addons/crm/crm_phonecall_view.xml2
-rw-r--r--addons/crm_helpdesk/crm_helpdesk_view.xml2
-rw-r--r--addons/email_template/email_template.py5
-rw-r--r--addons/email_template/tests/test_mail.py4
-rw-r--r--addons/email_template/wizard/mail_compose_message.py13
-rw-r--r--addons/event_sale/event_sale.py11
-rw-r--r--addons/gamification/data/badge.xml4
-rw-r--r--addons/gamification/data/cron.xml2
-rw-r--r--addons/gamification/data/goal_base.xml4
-rw-r--r--addons/gamification/models/challenge.py7
-rw-r--r--addons/gamification/security/gamification_security.xml7
-rw-r--r--addons/gamification_sale_crm/sale_crm_goals.xml2
-rw-r--r--addons/hr/static/description/index.html4
-rw-r--r--addons/hr_timesheet_sheet/hr_timesheet_sheet.py50
-rw-r--r--addons/mail/mail_mail_view.xml2
-rw-r--r--addons/mrp/static/description/index.html4
-rw-r--r--addons/note/__openerp__.py4
-rw-r--r--addons/note/note.py18
-rw-r--r--addons/note/static/description/index.html2
-rw-r--r--addons/point_of_sale/static/description/index.html6
-rw-r--r--addons/procurement/procurement.py8
-rw-r--r--addons/project_issue/project_issue_view.xml2
-rw-r--r--addons/purchase/purchase_view.xml4
-rw-r--r--addons/sale/sale_demo.xml1
-rw-r--r--addons/sale/sale_view.xml6
-rw-r--r--addons/sale_stock/sale_stock_demo.xml4
-rw-r--r--addons/stock/static/description/index.html2
-rw-r--r--addons/stock/stock.py95
-rw-r--r--addons/stock/wizard/stock_location_product.py4
-rw-r--r--addons/web/static/src/js/search.js5
-rw-r--r--addons/web/static/src/js/view_form.js2
-rw-r--r--addons/website/views/website_templates.xml2
-rw-r--r--addons/website_event_sale/views/website_event_sale.xml8
-rw-r--r--addons/website_hr_recruitment/security/website_hr_recruitment_security.xml2
-rw-r--r--addons/website_mail/views/snippets.xml6
50 files changed, 263 insertions, 164 deletions
diff --git a/addons/account/account.py b/addons/account/account.py
index b87caf547ab..aa5d507b3d2 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -1944,15 +1944,17 @@ class account_tax(osv.osv):
return super(account_tax, self).write(cr, uid, ids, vals, context=context)
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
+ if context is None:
+ context = {}
journal_pool = self.pool.get('account.journal')
- if context and context.has_key('type'):
+ if context.get('type'):
if context.get('type') in ('out_invoice','out_refund'):
args += [('type_tax_use','in',['sale','all'])]
elif context.get('type') in ('in_invoice','in_refund'):
args += [('type_tax_use','in',['purchase','all'])]
- if context and context.has_key('journal_id'):
+ if context.get('journal_id'):
journal = journal_pool.browse(cr, uid, context.get('journal_id'))
if journal.type in ('sale', 'purchase'):
args += [('type_tax_use','in',[journal.type,'all'])]
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index b521f3ff48c..61c397364b9 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -457,7 +457,7 @@
<filter name="invoices" string="Invoices" domain="[('state','not in',['draft','cancel'])]" help="Proforma/Open/Paid Invoices"/>
<filter name="unpaid" string="Unpaid" domain="[('state','=','open')]" help="Unpaid Invoices"/>
<separator/>
- <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="user_id" string="Salesperson"/>
<field name="period_id" string="Period"/>
<separator/>
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
index b48e842caf5..640ac90249b 100644
--- a/addons/account/account_move_line.py
+++ b/addons/account/account_move_line.py
@@ -1020,10 +1020,14 @@ class account_move_line(osv.osv):
part_rec_ids = [rec['reconcile_partial_id'][0] for rec in part_recs]
unlink_ids += rec_ids
unlink_ids += part_rec_ids
+ all_moves = obj_move_line.search(cr, uid, ['|',('reconcile_id', 'in', unlink_ids),('reconcile_partial_id', 'in', unlink_ids)])
+ all_moves = list(set(all_moves) - set(move_ids))
if unlink_ids:
if opening_reconciliation:
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
obj_move_rec.unlink(cr, uid, unlink_ids)
+ if all_moves:
+ obj_move_line.reconcile_partial(cr, uid, all_moves, 'auto',context=context)
return True
def unlink(self, cr, uid, ids, context=None, check=True):
diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml
index e518d8899b2..6e25c46168f 100644
--- a/addons/account/project/project_view.xml
+++ b/addons/account/project/project_view.xml
@@ -31,7 +31,7 @@
<search string="Analytic Account">
<field name="name" filter_domain="['|', ('name','ilike',self), ('code','ilike',self)]" string="Analytic Account"/>
<field name="date"/>
- <field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="manager_id"/>
<field name="parent_id"/>
<field name="user_id"/>
diff --git a/addons/account_analytic_analysis/account_analytic_analysis.py b/addons/account_analytic_analysis/account_analytic_analysis.py
index 99890a5f239..2205d52065b 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis.py
+++ b/addons/account_analytic_analysis/account_analytic_analysis.py
@@ -22,6 +22,7 @@ from dateutil.relativedelta import relativedelta
import datetime
import logging
import time
+import traceback
from openerp.osv import osv, fields
from openerp.osv.orm import intersect, except_orm
@@ -721,23 +722,40 @@ class account_analytic_account(osv.osv):
inv_obj.button_compute(cr, uid, [invoice_id], context=context)
return invoice_id
- def recurring_create_invoice(self, cr, uid, automatic=False, context=None):
+ def recurring_create_invoice(self, cr, uid, ids, context=None):
+ return self._recurring_create_invoice(cr, uid, ids, context=context)
+
+ def _cron_recurring_create_invoice(self, cr, uid, context=None):
+ return self._recurring_create_invoice(cr, uid, [], automatic=True, context=context)
+
+ def _recurring_create_invoice(self, cr, uid, ids, automatic=False, context=None):
context = context or {}
current_date = time.strftime('%Y-%m-%d')
-
- contract_ids = self.search(cr, uid, [('recurring_next_date','<=', current_date), ('state','=', 'open'), ('recurring_invoices','=', True)])
+ if ids:
+ contract_ids = ids
+ else:
+ contract_ids = self.search(cr, uid, [('recurring_next_date','<=', current_date), ('state','=', 'open'), ('recurring_invoices','=', True), ('type', '=', 'contract')])
for contract in self.browse(cr, uid, contract_ids, context=context):
- invoice_id = self._prepare_invoice(cr, uid, contract, context=context)
-
- next_date = datetime.datetime.strptime(contract.recurring_next_date or current_date, "%Y-%m-%d")
- interval = contract.recurring_interval
- if contract.recurring_rule_type == 'daily':
- new_date = next_date+relativedelta(days=+interval)
- elif contract.recurring_rule_type == 'weekly':
- new_date = next_date+relativedelta(weeks=+interval)
- else:
- new_date = next_date+relativedelta(months=+interval)
- self.write(cr, uid, [contract.id], {'recurring_next_date': new_date.strftime('%Y-%m-%d')}, context=context)
+ try:
+ invoice_id = self._prepare_invoice(cr, uid, contract, context=context)
+
+ next_date = datetime.datetime.strptime(contract.recurring_next_date or current_date, "%Y-%m-%d")
+ interval = contract.recurring_interval
+ if contract.recurring_rule_type == 'daily':
+ new_date = next_date+relativedelta(days=+interval)
+ elif contract.recurring_rule_type == 'weekly':
+ new_date = next_date+relativedelta(weeks=+interval)
+ else:
+ new_date = next_date+relativedelta(months=+interval)
+ self.write(cr, uid, [contract.id], {'recurring_next_date': new_date.strftime('%Y-%m-%d')}, context=context)
+ if automatic:
+ cr.commit()
+ except Exception:
+ if automatic:
+ cr.rollback()
+ _logger.error(traceback.format_exc())
+ else:
+ raise
return True
class account_analytic_account_summary_user(osv.osv):
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_cron.xml b/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
index 492278a87b5..0637c2ad276 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
@@ -93,7 +93,7 @@ OpenERP Automatic Email
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="model" eval="'account.analytic.account'"/>
- <field name="function" eval="'recurring_create_invoice'"/>
+ <field name="function" eval="'_cron_recurring_create_invoice'"/>
<field name="args" eval="'()'"/>
</record>
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
index d99be3db355..97fb15e9290 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
@@ -151,8 +151,10 @@
</group>
<separator string="Recurring Invoices" attrs="{'invisible': [('recurring_invoices','!=',True)]}"/>
<div>
- <field name="recurring_invoices" on_change="onchange_recurring_invoices(recurring_invoices, date_start)" class="oe_inline"/>
- <label for="recurring_invoices" />
+ <div attrs="{'invisible': [('type','!=', 'contract'), ('recurring_invoices', '=', False)]}">
+ <field name="recurring_invoices" on_change="onchange_recurring_invoices(recurring_invoices, date_start)" class="oe_inline" />
+ <label for="recurring_invoices" />
+ </div>
<button class="oe_link" name="recurring_create_invoice" attrs="{'invisible': [('recurring_invoices','!=',True)]}" string="⇒ create invoices" type="object" groups="base.group_no_one"/>
</div>
<group attrs="{'invisible': [('recurring_invoices','!=',True)]}">
diff --git a/addons/account_analytic_analysis/test/account_analytic_analysis.yml b/addons/account_analytic_analysis/test/account_analytic_analysis.yml
index 49668a2b781..4f594b6bed3 100644
--- a/addons/account_analytic_analysis/test/account_analytic_analysis.yml
+++ b/addons/account_analytic_analysis/test/account_analytic_analysis.yml
@@ -20,6 +20,7 @@
!record {model: account.analytic.account, id: contract_main}:
partner_id: base.main_partner
template_id: account_analytic_analysis.contract_template
+ type: contract
-
I check that the contract inherited from data of the template
-
@@ -32,7 +33,7 @@
I generate all invoices from contracts having recurring invoicing
-
!python {model: account.analytic.account}: |
- self.recurring_create_invoice(cr, uid)
+ self.recurring_create_invoice(cr, uid, [])
-
I test the generated invoice
-
diff --git a/addons/account_analytic_plans/account_analytic_plans.py b/addons/account_analytic_plans/account_analytic_plans.py
index 4cf12098fff..23a309c1dda 100644
--- a/addons/account_analytic_plans/account_analytic_plans.py
+++ b/addons/account_analytic_plans/account_analytic_plans.py
@@ -454,15 +454,10 @@ class account_bank_statement(osv.osv):
_inherit = "account.bank.statement"
_name = "account.bank.statement"
- def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
- account_move_line_pool = self.pool.get('account.move.line')
- account_bank_statement_line_pool = self.pool.get('account.bank.statement.line')
- st_line = account_bank_statement_line_pool.browse(cr, uid, st_line_id, context=context)
- result = super(account_bank_statement,self).create_move_from_st_line(cr, uid, st_line_id, company_currency_id, st_line_number, context=context)
- move = st_line.move_ids and st_line.move_ids[0] or False
- if move:
- for line in move.line_id:
- account_move_line_pool.write(cr, uid, [line.id], {'analytics_id':st_line.analytics_id.id}, context=context)
+ def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None):
+ result = super(account_bank_statement,self)._prepare_bank_move_line(cr, uid, st_line,
+ move_id, amount, company_currency_id, context=context)
+ result['analytics_id'] = st_line.analytics_id.id
return result
def button_confirm_bank(self, cr, uid, ids, context=None):
diff --git a/addons/account_anglo_saxon/invoice.py b/addons/account_anglo_saxon/invoice.py
index 81394bc926e..8ef17fa886c 100644
--- a/addons/account_anglo_saxon/invoice.py
+++ b/addons/account_anglo_saxon/invoice.py
@@ -123,6 +123,8 @@ class account_invoice_line(osv.osv):
if a == line['account_id'] and i_line.product_id.id == line['product_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:
+ standard_price = self.pool.get('res.currency').compute(cr, uid, company_currency, inv.currency_id.id, standard_price, context={'date': inv.date_invoice})
if i_line.product_id.cost_method != 'standard' and i_line.purchase_line_id:
#for average/fifo/lifo costing method, fetch real cost price from incomming moves
stock_move_obj = self.pool.get('stock.move')
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index 771c6e15bd8..a70684df1ad 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -783,6 +783,7 @@ class account_voucher(osv.osv):
total_credit += line.credit and line.amount_currency or 0.0
total_debit += line.debit and line.amount_currency or 0.0
+ remaining_amount = price
#voucher line creation
for line in account_move_lines:
@@ -803,13 +804,13 @@ class account_voucher(osv.osv):
'move_line_id':line.id,
'account_id':line.account_id.id,
'amount_original': amount_original,
- 'amount': (line.id in move_lines_found) and min(abs(price), amount_unreconciled) or 0.0,
+ 'amount': (line.id in move_lines_found) and min(abs(remaining_amount), amount_unreconciled) or 0.0,
'date_original':line.date,
'date_due':line.date_maturity,
'amount_unreconciled': amount_unreconciled,
'currency_id': line_currency_id,
}
- price -= rs['amount']
+ remaining_amount -= rs['amount']
#in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
#on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
if not move_lines_found:
@@ -937,19 +938,17 @@ class account_voucher(osv.osv):
def cancel_voucher(self, cr, uid, ids, context=None):
reconcile_pool = self.pool.get('account.move.reconcile')
move_pool = self.pool.get('account.move')
-
+ move_line_pool = self.pool.get('account.move.line')
for voucher in self.browse(cr, uid, ids, context=context):
# refresh to make sure you don't unlink an already removed move
voucher.refresh()
- recs = []
for line in voucher.move_ids:
if line.reconcile_id:
- recs += [line.reconcile_id.id]
- if line.reconcile_partial_id:
- recs += [line.reconcile_partial_id.id]
-
- reconcile_pool.unlink(cr, uid, recs)
-
+ move_lines = [move_line.id for move_line in line.reconcile_id.line_id]
+ move_lines.remove(line.id)
+ reconcile_pool.unlink(cr, uid, [line.reconcile_id.id])
+ if len(move_lines) >= 2:
+ move_line_pool.reconcile_partial(cr, uid, move_lines, 'auto',context=context)
if voucher.move_id:
move_pool.button_cancel(cr, uid, [voucher.move_id.id])
move_pool.unlink(cr, uid, [voucher.move_id.id])
diff --git a/addons/account_voucher/test/sales_payment.yml b/addons/account_voucher/test/sales_payment.yml
index 3679c34dc52..ed9305a320c 100644
--- a/addons/account_voucher/test/sales_payment.yml
+++ b/addons/account_voucher/test/sales_payment.yml
@@ -44,6 +44,8 @@
!python {model: account.voucher}: |
vals = {}
journal_id = self.default_get(cr, uid, ['journal_id']).get('journal_id',None)
+ voucher = self.recompute_voucher_lines(cr, uid, [], ref("base.res_partner_19"), journal_id, 450.0, ref('base.EUR'), 'receipt', False)
+ assert (voucher['value'].get('writeoff_amount') == 0.0), "Writeoff amount calculated by recompute_voucher_lines() is not 0.0"
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_19"), journal_id, 0.0, 1, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
@@ -64,6 +66,7 @@
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
+ assert (voucher_id.writeoff_amount == 0.0), "Writeoff amount is not 0.0"
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
self.signal_proforma_voucher(cr, uid, [voucher_id.id])
diff --git a/addons/base_geolocalize/views/res_partner_view.xml b/addons/base_geolocalize/views/res_partner_view.xml
index 24cc8d2d21d..1bd537ae3ff 100644
--- a/addons/base_geolocalize/views/res_partner_view.xml
+++ b/addons/base_geolocalize/views/res_partner_view.xml
@@ -8,7 +8,7 @@
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook[last()]" position="inside">
- <page string="Geo Localization" name="geo_localization" groups="base.group_no_one">
+ <page string="Geo Localization" name="geo_localization">
<group colspan="2" col="2">
<separator string="Geo Localization" colspan="2"/>
<button
diff --git a/addons/calendar/calendar.py b/addons/calendar/calendar.py
index 6dff8ee2e8b..d66b7f769bc 100644
--- a/addons/calendar/calendar.py
+++ b/addons/calendar/calendar.py
@@ -994,7 +994,6 @@ class calendar_event(osv.Model):
sort_fields[ord] = '%s-%s' % (browse_event[ord], r_date.strftime("%Y%m%d%H%M%S"))
else:
sort_fields[ord] = browse_event[ord]
- 'If we sort on FK, we obtain a browse_record, so we need to sort on name_get'
if type(browse_event[ord]) is openerp.osv.orm.browse_record:
name_get = browse_event[ord].name_get()
if len(name_get) and len(name_get[0]) >= 2:
@@ -1397,6 +1396,14 @@ class calendar_event(osv.Model):
'flags': {'form': {'action_buttons': True, 'options': {'mode': 'edit'}}}
}
+ def _name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
+ for arg in args:
+ if arg[0] == 'id':
+ for n, calendar_id in enumerate(arg[2]):
+ if isinstance(calendar_id, str):
+ arg[2][n] = calendar_id.split('-')[0]
+ return super(calendar_event, self)._name_search(cr, user, name=name, args=args, operator=operator, context=context, limit=limit, name_get_uid=name_get_uid)
+
def write(self, cr, uid, ids, values, context=None):
def _only_changes_to_apply_on_real_ids(field_names):
''' return True if changes are only to be made on the real ids'''
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index cfa0c352253..a7f3012f2ce 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -327,7 +327,7 @@
<field name="categ_ids" string="Tag" filter_domain="[('categ_ids', 'ilike', self)]"/>
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
- <field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="create_date"/>
<field name="country_id" context="{'invisible_country': False}"/>
<separator/>
@@ -547,7 +547,7 @@
<field name="categ_ids" string="Tag" filter_domain="[('categ_ids', 'ilike', self)]"/>
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
- <field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="stage_id" domain="[]"/>
<field name="probability"/>
<separator/>
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 60b5934ac53..b71eee4220b 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -176,7 +176,7 @@
<separator/>
<filter string="Phone Calls Assigned to Me or My Team(s)" icon="terp-personal+" domain="['|', ('section_id.user_id','=',uid), ('user_id', '=', uid)]"
help="Phone Calls Assigned to the current user or with a team having the current user as team leader"/>
- <field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="user_id"/>
<field name="section_id" string="Sales Team"
groups="base.group_multi_salesteams"/>
diff --git a/addons/crm_helpdesk/crm_helpdesk_view.xml b/addons/crm_helpdesk/crm_helpdesk_view.xml
index 3065d2fa6af..79615715f5f 100644
--- a/addons/crm_helpdesk/crm_helpdesk_view.xml
+++ b/addons/crm_helpdesk/crm_helpdesk_view.xml
@@ -52,7 +52,7 @@
</group>
<group string="Categorization">
<field name="priority"/>
- <field name="categ_id" domain="[('object_id.model', '=', 'crm.helpdesk')]"/>
+ <field name="categ_id" domain="[('object_id.model', '=', 'crm.helpdesk')]" context="{'object_name': 'crm.helpdesk'}"/>
<field name="channel_id"/>
</group>
</group>
diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py
index dd9ed49d3ef..7321d9dca08 100644
--- a/addons/email_template/email_template.py
+++ b/addons/email_template/email_template.py
@@ -431,7 +431,7 @@ class email_template(osv.osv):
is taken from template definition)
:returns: a dict containing all relevant fields for creating a new
mail.mail entry, with one extra key ``attachments``, in the
- format expected by :py:meth:`mail_thread.message_post`.
+ format [(report_name, data)] where data is base64 encoded.
"""
if context is None:
context = {}
@@ -492,7 +492,8 @@ class email_template(osv.osv):
result, format = self.pool['report'].get_pdf(cr, uid, [res_id], report_service, context=ctx), 'pdf'
else:
result, format = openerp.report.render_report(cr, uid, [res_id], report_service, {'model': template.model}, ctx)
-
+
+ # TODO in trunk, change return format to binary to match message_post expected format
result = base64.b64encode(result)
if not report_name:
report_name = 'report.' + report_service
diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py
index 8bc6d62017c..beda74d0853 100644
--- a/addons/email_template/tests/test_mail.py
+++ b/addons/email_template/tests/test_mail.py
@@ -62,7 +62,7 @@ class test_message_compose(TestMail):
'name': 'Pigs Template',
'subject': '${object.name}',
'body_html': '${object.description}',
- 'user_signature': True,
+ 'user_signature': False,
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
'email_to': 'b@b.b, c@c.c',
'email_cc': 'd@d.d'
@@ -157,7 +157,7 @@ class test_message_compose(TestMail):
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = [p_a_id]
self.assertEqual(compose.subject, '${object.name}', 'mail.compose.message subject incorrect')
- self.assertEqual(compose.body, '<p>${object.description}</p>', 'mail.compose.message body incorrect')
+ self.assertEqual(compose.body, '<p>${object.description}</p>', 'mail.compose.message body incorrect') # todo: check signature
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# 2. Post the comment, get created message
diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py
index 676f11b23e3..7d148c87e3c 100644
--- a/addons/email_template/wizard/mail_compose_message.py
+++ b/addons/email_template/wizard/mail_compose_message.py
@@ -87,9 +87,16 @@ class mail_compose_message(osv.TransientModel):
""" - mass_mailing: we cannot render, so return the template values
- normal mode: return rendered values """
if template_id and composition_mode == 'mass_mail':
- fields = ['subject', 'body_html', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id']
- template_values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
- values = dict((field, template_values[field]) for field in fields if template_values.get(field))
+ fields = ['subject', 'body_html', 'email_from', 'reply_to', 'mail_server_id']
+ template = self.pool['email.template'].browse(cr, uid, template_id, context=context)
+ values = dict((field, getattr(template, field)) for field in fields if getattr(template, field))
+ if template.attachment_ids:
+ values['attachment_ids'] = [att.id for att in template.attachment_ids]
+ if template.mail_server_id:
+ values['mail_server_id'] = template.mail_server_id.id
+ if template.user_signature and 'body_html' in values:
+ signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
+ values['body_html'] = tools.append_content_to_html(values['body_html'], signature)
elif template_id:
values = self.generate_email_for_composer_batch(cr, uid, template_id, [res_id], context=context)[res_id]
# transform attachments into attachment_ids; not attached to the document because this will
diff --git a/addons/event_sale/event_sale.py b/addons/event_sale/event_sale.py
index 8b9352cb91b..b7cb37571a4 100644
--- a/addons/event_sale/event_sale.py
+++ b/addons/event_sale/event_sale.py
@@ -167,12 +167,23 @@ class event_ticket(osv.osv):
if ticket.seats_max > 0 else None
return res
+ def _is_expired(self, cr, uid, ids, field_name, args, context=None):
+ # FIXME: A ticket is considered expired when the deadline is passed. The deadline should
+ # be considered in the timezone of the event, not the timezone of the user!
+ # Until we add a TZ on the event we'll use the context's current date, more accurate
+ # than using UTC all the time.
+ current_date = fields.date.context_today(self, cr, uid, context=context)
+ return {ticket.id: ticket.deadline and ticket.deadline < current_date
+ for ticket in self.browse(cr, uid, ids, context=context)}
+
+
_columns = {
'name': fields.char('Name', size=64, required=True, translate=True),
'event_id': fields.many2one('event.event', "Event", required=True, ondelete='cascade'),
'product_id': fields.many2one('product.product', 'Product', required=True, domain=[("event_type_id", "!=", False)]),
'registration_ids': fields.one2many('event.registration', 'event_ticket_id', 'Registrations'),
'deadline': fields.date("Sales End"),
+ 'is_expired': fields.function(_is_expired, type='boolean', string='Is Expired'),
'price': fields.float('Price'),
'seats_max': fields.integer('Maximum Avalaible Seats', oldname='register_max', help="You can for each event define a maximum registration level. If you have too much registrations you are not able to confirm your event. (put 0 to ignore this rule )"),
'seats_reserved': fields.function(_get_seats, string='Reserved Seats', type='integer', multi='seats_reserved'),
diff --git a/addons/gamification/data/badge.xml b/addons/gamification/data/badge.xml
index 33d02bf016e..cc9df921309 100644
--- a/addons/gamification/data/badge.xml
+++ b/addons/gamification/data/badge.xml
@@ -41,10 +41,6 @@
<field name="description">Badge Granted</field>
</record>
- </data>
-
-
- <data noupdate="0">
<record id="email_template_badge_received" model="email.template">
<field name="name">Received Badge</field>
diff --git a/addons/gamification/data/cron.xml b/addons/gamification/data/cron.xml
index 8585771c97d..105f7d25681 100644
--- a/addons/gamification/data/cron.xml
+++ b/addons/gamification/data/cron.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
- <data>
+ <data noupdate="1">
<record forcecreate="True" id="ir_cron_check_challenge"
model="ir.cron">
<field name="name">Run Goal Challenge Checker</field>
diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml
index c12763025f6..f249e566b9f 100644
--- a/addons/gamification/data/goal_base.xml
+++ b/addons/gamification/data/goal_base.xml
@@ -90,10 +90,6 @@
]]></field>
</record>
- </data>
-
- <data>
-
<!-- goal definitions -->
<record model="gamification.goal.definition" id="definition_base_timezone">
<field name="name">Set your Timezone</field>
diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py
index a0c4b638ae3..ecb4c495d94 100644
--- a/addons/gamification/models/challenge.py
+++ b/addons/gamification/models/challenge.py
@@ -200,7 +200,6 @@ class gamification_challenge(osv.Model):
'visibility_mode': 'personal',
'report_message_frequency': 'never',
'last_report_date': fields.date.today,
- 'start_date': fields.date.today,
'manager_id': lambda s, cr, uid, c: uid,
'category': 'hr',
'reward_failure': False,
@@ -269,13 +268,15 @@ class gamification_challenge(osv.Model):
planned_challenge_ids = self.search(cr, uid, [
('state', '=', 'draft'),
('start_date', '<=', fields.date.today())])
- self.write(cr, uid, planned_challenge_ids, {'state': 'inprogress'}, context=context)
+ if planned_challenge_ids:
+ self.write(cr, uid, planned_challenge_ids, {'state': 'inprogress'}, context=context)
# close scheduled challenges
planned_challenge_ids = self.search(cr, uid, [
('state', '=', 'inprogress'),
('end_date', '>=', fields.date.today())])
- self.write(cr, uid, planned_challenge_ids, {'state': 'done'}, context=context)
+ if planned_challenge_ids:
+ self.write(cr, uid, planned_challenge_ids, {'state': 'done'}, context=context)
if not ids:
ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context)
diff --git a/addons/gamification/security/gamification_security.xml b/addons/gamification/security/gamification_security.xml
index 904ba50721e..5339b400061 100644
--- a/addons/gamification/security/gamification_security.xml
+++ b/addons/gamification/security/gamification_security.xml
@@ -39,5 +39,12 @@
<field name="domain_force">[(1, '=', 1)]</field>
</record>
+ <record id="goal_global_multicompany" model="ir.rule">
+ <field name="name">User can only see his/her goals or goal from the same challenge in board visibility</field>
+ <field name="model_id" ref="model_gamification_goal"/>
+ <field name="domain_force">[('user_id.company_id', 'child_of', [user.company_id.id])]</field>
+ <field name="global" eval="True"/>
+ </record>
+
</data>
</openerp>
diff --git a/addons/gamification_sale_crm/sale_crm_goals.xml b/addons/gamification_sale_crm/sale_crm_goals.xml
index ffb3a24318a..f42585fe59a 100644
--- a/addons/gamification_sale_crm/sale_crm_goals.xml
+++ b/addons/gamification_sale_crm/sale_crm_goals.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
- <data>
+ <data noupdate="1">
<!-- goal definitions -->
<record model="gamification.goal.definition" id="definition_crm_tot_invoices">
diff --git a/addons/hr/static/description/index.html b/addons/hr/static/description/index.html
index f97cb462fe3..55e54aa92fb 100644
--- a/addons/hr/static/description/index.html
+++ b/addons/hr/static/description/index.html
@@ -28,7 +28,7 @@ Get all your HR operations managed easily: knowledge sharing, recruitments, appr
<h2 class="oe_slogan">Manage Your Employees</h2>
<div class="oe_span6">
<p class='oe_mt32'>
-Oversee all important information in your company address book. Some information are restricted to HR managers, others are public to easily find colleagues.
+Oversee all important information in your company address book. Some information are restricted to HR managers, others are public to easily look colleagues.
</p><p>
Record employee contracts and get alerts when they have to be renewed.
</p>
@@ -154,7 +154,7 @@ Inspire achievement with challenges, goals and rewards. Define clear objectives
</p>
</div>
<div class="oe_span4 oe_centered">
- <h3>Personnal Objectives</h3>
+ <h3>Personal Objectives</h3>
<div class="oe_row_img">
<img class="oe_picture" src="crm_game_02.png">
</div>
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index e8349f68a58..6c9156f6be0 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -62,28 +62,56 @@ class hr_timesheet_sheet(osv.osv):
def copy(self, cr, uid, ids, *args, **argv):
raise osv.except_osv(_('Error!'), _('You cannot duplicate a timesheet.'))
- def create(self, cr, uid, vals, *args, **argv):
+ def create(self, cr, uid, vals, context=None):
if 'employee_id' in vals:
- if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).user_id:
+ if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).user_id:
raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must assign it to a user.'))
- if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).product_id:
+ if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).product_id:
raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must link the employee to a product, like \'Consultant\'.'))
- if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).journal_id:
+ if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).journal_id:
raise osv.except_osv(_('Configuration Error!'), _('In order to create a timesheet for this employee, you must assign an analytic journal to the employee, like \'Timesheet Journal\'.'))
- return super(hr_timesheet_sheet, self).create(cr, uid, vals, *args, **argv)
+ if vals.get('attendances_ids'):
+ # If attendances, we sort them by date asc before writing them, to satisfy the alternance constraint
+ vals['attendances_ids'] = self.sort_attendances(cr, uid, vals['attendances_ids'], context=context)
+ return super(hr_timesheet_sheet, self).create(cr, uid, vals, context=context)
- def write(self, cr, uid, ids, vals, *args, **argv):
+ def write(self, cr, uid, ids, vals, context=None):
if 'employee_id' in vals:
- new_user_id = self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).user_id.id or False
+ new_user_id = self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).user_id.id or False
if not new_user_id:
raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must assign it to a user.'))
- if not self._sheet_date(cr, uid, ids, forced_user_id=new_user_id):
+ if not self._sheet_date(cr, uid, ids, forced_user_id=new_user_id, context=context):
raise osv.except_osv(_('Error!'), _('You cannot have 2 timesheets that overlap!\nYou should use the menu \'My Timesheet\' to avoid this problem.'))
- if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).product_id:
+ if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).product_id:
raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must link the employee to a product.'))
- if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).journal_id:
+ if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id'], context=context).journal_id:
raise osv.except_osv(_('Configuration Error!'), _('In order to create a timesheet for this employee, you must assign an analytic journal to the employee, like \'Timesheet Journal\'.'))
- return super(hr_timesheet_sheet, self).write(cr, uid, ids, vals, *args, **argv)
+ if vals.get('attendances_ids'):
+ # If attendances, we sort them by date asc before writing them, to satisfy the alternance constraint
+ # In addition to the date order, deleting attendances are done before inserting attendances
+ vals['attendances_ids'] = self.sort_attendances(cr, uid, vals['attendances_ids'], context=context)
+ res = super(hr_timesheet_sheet, self).write(cr, uid, ids, vals, context=context)
+ if vals.get('attendances_ids'):
+ for timesheet in self.browse(cr, uid, ids):
+ if not self.pool['hr.attendance']._altern_si_so(cr, uid, [att.id for att in timesheet.attendances_ids]):
+ raise osv.except_osv(_('Warning !'), _('Error ! Sign in (resp. Sign out) must follow Sign out (resp. Sign in)'))
+ return res
+
+ def sort_attendances(self, cr, uid, attendance_tuples, context=None):
+ date_attendances = []
+ for att_tuple in attendance_tuples:
+ if att_tuple[0] in [0,1,4]:
+ if att_tuple[0] in [0,1]:
+ name = att_tuple[2]['name']
+ else:
+ name = self.pool['hr.attendance'].browse(cr, uid, att_tuple[1]).name
+ date_attendances.append((1, name, att_tuple))
+ elif att_tuple[0] in [2,3]:
+ date_attendances.append((0, self.pool['hr.attendance'].browse(cr, uid, att_tuple[1]).name, att_tuple))
+ else:
+ date_attendances.append((0, False, att_tuple))
+ date_attendances.sort()
+ return [att[2] for att in date_attendances]
def button_confirm(self, cr, uid, ids, context=None):
for sheet in self.browse(cr, uid, ids, context=context):
diff --git a/addons/mail/mail_mail_view.xml b/addons/mail/mail_mail_view.xml
index e259d28a2b7..52a8d2beadf 100644
--- a/addons/mail/mail_mail_view.xml
+++ b/addons/mail/mail_mail_view.xml
@@ -92,7 +92,7 @@
<field name="model">mail.mail</field>
<field name="arch" type="xml">
<search string="Email Search">
- <field name="email_from" filter_domain="['|' '|',('email_from','ilike',self), ('email_to','ilike',self), ('subject','ilike',self)]" string="Email"/>
+ <field name="email_from" filter_domain="['|', '|',('email_from','ilike',self), ('email_to','ilike',self), ('subject','ilike',self)]" string="Email"/>
<field name="date"/>
<filter icon="terp-camera_test" name="received" string="Received" domain="[('state','=','received')]"/>
<filter icon="terp-call-start" name="outgoing" string="Outgoing" domain="[('state','=','outgoing')]"/>
diff --git a/addons/mrp/static/description/index.html b/addons/mrp/static/description/index.html
index d44da3f37b1..d6524b6e554 100644
--- a/addons/mrp/static/description/index.html
+++ b/addons/mrp/static/description/index.html
@@ -63,7 +63,7 @@ manufacturing orders.
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
- <h2 class="oe_slogan">Get Flexibility In All Opertions</h2>
+ <h2 class="oe_slogan">Get Flexibility In All Operations</h2>
<div class="oe_span6">
<p class="oe_mt32">
Edit manually all proposed operations at any level of the progress.
@@ -110,7 +110,7 @@ meets your delivery schedule dates.
<div class="oe_span12">
<p>
Organize manufacturing orders and work orders the way you like it. Process next
-orders from the list view, control inthe calendar view and edit the proposed
+orders from the list view, control in the calendar view and edit the proposed
schedule in the Gantt view.
</p>
</div>
diff --git a/addons/note/__openerp__.py b/addons/note/__openerp__.py
index 2653c558923..e94a5f60181 100644
--- a/addons/note/__openerp__.py
+++ b/addons/note/__openerp__.py
@@ -27,8 +27,8 @@
This module allows users to create their own notes inside OpenERP
=================================================================
-Use notes to write meeting minutes, organize ideas, organize personnal todo
-lists, etc. Each user manages his own personnal Notes. Notes are available to
+Use notes to write meeting minutes, organize ideas, organize personal todo
+lists, etc. Each user manages his own personal Notes. Notes are available to
their authors only, but they can share notes to others users so that several
people can work on the same note in real time. It's very efficient to share
meeting minutes.
diff --git a/addons/note/note.py b/addons/note/note.py
index 38b2395a852..2d6e5f8c098 100644
--- a/addons/note/note.py
+++ b/addons/note/note.py
@@ -123,16 +123,15 @@ class note_note(osv.osv):
current_stage_ids = self.pool.get('note.stage').search(cr,uid,[('user_id','=',uid)], context=context)
if current_stage_ids: #if the user have some stages
-
- #dict of stages: map les ids sur les noms
- stage_name = dict(self.pool.get('note.stage').name_get(cr, uid, current_stage_ids, context=context))
+ stages = self.pool['note.stage'].browse(cr, uid, current_stage_ids, context=context)
result = [{ #notes by stage for stages user
'__context': {'group_by': groupby[1:]},
- '__domain': domain + [('stage_ids.id', '=', current_stage_id)],
- 'stage_id': (current_stage_id, stage_name[current_stage_id]),
- 'stage_id_count': self.search(cr,uid, domain+[('stage_ids', '=', current_stage_id)], context=context, count=True)
- } for current_stage_id in current_stage_ids]
+ '__domain': domain + [('stage_ids.id', '=', stage.id)],
+ 'stage_id': (stage.id, stage.name),
+ 'stage_id_count': self.search(cr,uid, domain+[('stage_ids', '=', stage.id)], context=context, count=True),
+ '__fold': stage.fold,
+ } for stage in stages]
#note without user's stage
nb_notes_ws = self.search(cr,uid, domain+[('stage_ids', 'not in', current_stage_ids)], context=context, count=True)
@@ -148,8 +147,9 @@ class note_note(osv.osv):
result = [{
'__context': {'group_by': groupby[1:]},
'__domain': domain + [dom_not_in],
- 'stage_id': (current_stage_ids[0], stage_name[current_stage_ids[0]]),
- 'stage_id_count':nb_notes_ws
+ 'stage_id': (stages[0].id, stages[0].name),
+ 'stage_id_count':nb_notes_ws,
+ '__fold': stages[0].name,
}] + result
else: # if stage_ids is empty
diff --git a/addons/note/static/description/index.html b/addons/note/static/description/index.html
index dc688859334..b9a60d3735d 100644
--- a/addons/note/static/description/index.html
+++ b/addons/note/static/description/index.html
@@ -12,7 +12,7 @@
</div>
<div class="oe_span6">
<p class="oe_mt32">
-Organize yourself with efficient todo lists and notes. From personnal tasks to collaborative meeting minutes, increase your user's productivity by giving them the tools to prioritize their work, share their ideas and collaborate on documents.
+Organize yourself with efficient todo lists and notes. From personal tasks to collaborative meeting minutes, increase your user's productivity by giving them the tools to prioritize their work, share their ideas and collaborate on documents.
</p>
<div class="oe_centeralign oe_websiteonly">
<a href="http://www.openerp.com/start?app=note" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
diff --git a/addons/point_of_sale/static/description/index.html b/addons/point_of_sale/static/description/index.html
index 7f1b7a5c097..cecafc69b68 100644
--- a/addons/point_of_sale/static/description/index.html
+++ b/addons/point_of_sale/static/description/index.html
@@ -117,9 +117,9 @@
</div>
<div class='oe_span4 '>
<img class="oe_picture oe_screenshot" src="pos_ui_02.png">
- <h3>Blasting fast search</h3>
+ <h3>Blazing fast search</h3>
<p>
- Scan products, browse through hyerarchical categories, or get quick
+ Scan products, browse through hierarchical categories, or get quick
information about products with the blasting fast filter accross
all your products.
</p>
@@ -135,7 +135,7 @@
</div>
<div class='oe_span6'>
<p>
- Consolidate all your sales channel in real time: stores, ecommerce, sales teams.
+ Consolidate all your sales channels in real time: stores, ecommerce, sales teams.
Get real time control of the inventory and accurate forecasts to manage procurements.
</p>
<p>
diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index 1e7076d9c8f..e7a2e6a1c86 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -558,14 +558,14 @@ class stock_warehouse_orderpoint(osv.osv):
]
def default_get(self, cr, uid, fields, context=None):
+ warehouse_obj = self.pool.get('stock.warehouse')
res = super(stock_warehouse_orderpoint, self).default_get(cr, uid, fields, context)
# default 'warehouse_id' and 'location_id'
if 'warehouse_id' not in res:
- warehouse = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'warehouse0', context)
- res['warehouse_id'] = warehouse.id
+ warehouse_ids = res.get('company_id') and warehouse_obj.search(cr, uid, [('company_id', '=', res['company_id'])], limit=1, context=context) or []
+ res['warehouse_id'] = warehouse_ids and warehouse_ids[0] or False
if 'location_id' not in res:
- warehouse = self.pool.get('stock.warehouse').browse(cr, uid, res['warehouse_id'], context)
- res['location_id'] = warehouse.lot_stock_id.id
+ res['location_id'] = res.get('warehouse_id') and warehouse_obj.browse(cr, uid, res['warehouse_id'], context).lot_stock_id.id or False
return res
def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, context=None):
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index 3af9ee608d6..46dd2a0babf 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -142,7 +142,7 @@
<search string="Issue Tracker Search">
<field name="name" string="Issue" filter_domain="['|', '|', '|', ('partner_id','child_of',self), ('description','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<field name="id"/>
- <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
+ <field name="partner_id" operator="child_of"/>
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
<filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/>
<separator/>
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 209bad47495..9b43b2cdc12 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -273,7 +273,7 @@
<filter icon="terp-emblem-important" name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]" help="Purchase order which are in the exception state"/>
<separator/>
<filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
- <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="create_uid"/>
<group expand="0" string="Group By...">
@@ -300,7 +300,7 @@
<filter icon="terp-emblem-important" name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]" help="Purchase orders which are in exception state"/>
<separator/>
<filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
- <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="create_uid"/>
<group expand="0" string="Group By...">
diff --git a/addons/sale/sale_demo.xml b/addons/sale/sale_demo.xml
index 4653058c7bd..0c6e92e86ff 100644
--- a/addons/sale/sale_demo.xml
+++ b/addons/sale/sale_demo.xml
@@ -324,7 +324,6 @@ Thanks!</field>
<field name="type">service</field>
<field name="list_price">150.0</field>
<field name="standard_price">100.0</field>
- <field name="supply_method">produce</field> <!-- TODO this is a procurement field, which is not a sale dependency -->
<field name="uom_id" ref="product.product_uom_day"/>
<field name="uom_po_id" ref="product.product_uom_day"/>
<field name="company_id" eval="[]"/>
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index c9ffb94b985..afb320001a9 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -253,7 +253,7 @@
<filter icon="terp-dolar_ok!" string="Done" domain="[('state','=','done')]" help="Sales Order done"/>
<separator/>
<filter string="My" domain="[('user_id','=',uid)]" help="My Sales Orders" icon="terp-personal" name="my_sale_orders_filter"/>
- <field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
+ <field name="partner_id" operator="child_of"/>
<field name="user_id"/>
<field name="project_id"/>
<group expand="0" string="Group By...">
@@ -421,7 +421,7 @@
<separator/>
<filter string="My Sales Order Lines" icon="terp-personnal" domain="[('salesman_id','=',uid)]" help="Sales Order Lines related to a Sales Order of mine"/>
<field name="order_id"/>
- <field name="order_partner_id" filter_domain="[('order_partner_id', 'child_of', self)]"/>
+ <field name="order_partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="salesman_id"/>
<group expand="0" string="Group By...">
@@ -447,7 +447,7 @@
<separator/>
<filter string="My Sales Order Lines" icon="terp-personal" domain="[('salesman_id','=',uid)]" help="My Sales Order Lines"/>
<field name="order_id"/>
- <field name="order_partner_id" filter_domain="[('order_partner_id', 'child_of', self)]"/>
+ <field name="order_partner_id" operator="child_of"/>
<field name="product_id"/>
<field name="salesman_id"/>
<group expand="0" string="Group By...">
diff --git a/addons/sale_stock/sale_stock_demo.xml b/addons/sale_stock/sale_stock_demo.xml
index 2e7b641659d..42c09b7e9f0 100644
--- a/addons/sale_stock/sale_stock_demo.xml
+++ b/addons/sale_stock/sale_stock_demo.xml
@@ -54,6 +54,10 @@
<field name="type">make_to_order</field>
</record>
+ <record id="sale.advance_product_0" model="product.product">
+ <field name="supply_method">produce</field>
+ </record>
+
<!-- Run all schedulers -->
<function model="procurement.order" name="run_scheduler"/>
diff --git a/addons/stock/static/description/index.html b/addons/stock/static/description/index.html
index dd7fbe568f7..1ee9047db42 100644
--- a/addons/stock/static/description/index.html
+++ b/addons/stock/static/description/index.html
@@ -69,7 +69,7 @@ planning and jobs with the scheduler to reduce your process time.
<p class='oe_mt32'>
Get your pickings, packings, receptions and internal moves scheduled
automatically by OpenERP using your own routing rules. Define push and pull
-rules to organize a warehouse or to manage produts's moves between several
+rules to organize a warehouse or to manage products moves between several
warehouses.
</p>
</div>
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 7e73d7fcd53..5276e7f21e5 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -718,7 +718,6 @@ class stock_picking(osv.osv):
default = {}
default = default.copy()
picking_obj = self.browse(cr, uid, id, context=context)
- move_obj = self.pool.get('stock.move')
if ('name' not in default) or (picking_obj.name == '/'):
seq_obj_name = 'stock.picking.' + picking_obj.type
default['name'] = self.pool.get('ir.sequence').get(cr, uid, seq_obj_name)
@@ -727,10 +726,6 @@ class stock_picking(osv.osv):
if 'invoice_state' not in default and picking_obj.invoice_state == 'invoiced':
default['invoice_state'] = '2binvoiced'
res = super(stock_picking, self).copy(cr, uid, id, default, context)
- if res:
- picking_obj = self.browse(cr, uid, res, context=context)
- for move in picking_obj.move_lines:
- move_obj.write(cr, uid, [move.id], {'tracking_id': False, 'prodlot_id': False, 'move_history_ids2': [(6, 0, [])], 'move_history_ids': [(6, 0, [])]})
return res
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
@@ -1797,12 +1792,15 @@ class stock_move(osv.osv):
_('Quantities, Units of Measure, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator).'))
return super(stock_move, self).write(cr, uid, ids, vals, context=context)
- def copy(self, cr, uid, id, default=None, context=None):
+ def copy_data(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
default = default.copy()
- default.update({'move_history_ids2': [], 'move_history_ids': []})
- return super(stock_move, self).copy(cr, uid, id, default, context=context)
+ default.setdefault('tracking_id', False)
+ default.setdefault('prodlot_id', False)
+ default.setdefault('move_history_ids', [])
+ default.setdefault('move_history_ids2', [])
+ return super(stock_move, self).copy_data(cr, uid, id, default, context=context)
def _auto_init(self, cursor, context=None):
res = super(stock_move, self)._auto_init(cursor, context=context)
@@ -2072,41 +2070,46 @@ class stock_move(osv.osv):
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
- for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
- ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
- if picking:
- # name of new picking according to its type
- if ptype == 'internal':
- new_pick_name = seq_obj.get(cr, uid,'stock.picking')
- else :
- new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
- pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
- # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order
- old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
- if old_ptype != picking.type:
- old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
- self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context)
- else:
- pickid = False
- for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo:
- new_id = move_obj.copy(cr, uid, move.id, {
- 'location_id': move.location_dest_id.id,
- 'location_dest_id': loc.id,
- 'date': time.strftime('%Y-%m-%d'),
- 'picking_id': pickid,
- 'state': 'waiting',
- 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
- 'move_history_ids': [],
- 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
- 'move_history_ids2': []}
- )
- move_obj.write(cr, uid, [move.id], {
- 'move_dest_id': new_id,
- 'move_history_ids': [(4, new_id)]
- })
- new_moves.append(self.browse(cr, uid, [new_id])[0])
- if pickid:
- self.pool.get('stock.picking').signal_button_confirm(cr, uid, [pickid])
+ for picking, chained_moves in self._chain_compute(cr, uid, moves, context=context).items():
+ # We group the moves by automatic move type, so it creates different pickings for different types
+ moves_by_type = {}
+ for move in chained_moves:
+ moves_by_type.setdefault(move[1][1], []).append(move)
+ for todo in moves_by_type.values():
+ ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
+ if picking:
+ # name of new picking according to its type
+ if ptype == 'internal':
+ new_pick_name = seq_obj.get(cr, uid,'stock.picking')
+ else :
+ new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
+ pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
+ # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order
+ old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
+ if old_ptype != picking.type:
+ old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
+ self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context)
+ else:
+ pickid = False
+ for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo:
+ new_id = move_obj.copy(cr, uid, move.id, {
+ 'location_id': move.location_dest_id.id,
+ 'location_dest_id': loc.id,
+ 'date': time.strftime('%Y-%m-%d'),
+ 'picking_id': pickid,
+ 'state': 'waiting',
+ 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
+ 'move_history_ids': [],
+ 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
+ 'move_history_ids2': []}
+ )
+ move_obj.write(cr, uid, [move.id], {
+ 'move_dest_id': new_id,
+ 'move_history_ids': [(4, new_id)]
+ })
+ new_moves.append(self.browse(cr, uid, [new_id])[0])
+ if pickid:
+ self.pool.get('stock.picking').signal_button_confirm(cr, uid, [pickid])
if new_moves:
new_moves += self.create_chained_picking(cr, uid, new_moves, context)
return new_moves
@@ -2996,6 +2999,9 @@ class stock_picking_in(osv.osv):
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
return self.pool.get('stock.picking').read(cr, uid, ids, fields=fields, context=context, load=load)
+ def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
+ return self.pool['stock.picking'].read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
+
def check_access_rights(self, cr, uid, operation, raise_exception=True):
#override in order to redirect the check of acces rights on the stock.picking object
return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
@@ -3076,6 +3082,9 @@ class stock_picking_out(osv.osv):
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
return self.pool.get('stock.picking').read(cr, uid, ids, fields=fields, context=context, load=load)
+ def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
+ return self.pool['stock.picking'].read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
+
def check_access_rights(self, cr, uid, operation, raise_exception=True):
#override in order to redirect the check of acces rights on the stock.picking object
return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
diff --git a/addons/stock/wizard/stock_location_product.py b/addons/stock/wizard/stock_location_product.py
index ef7c9848160..62f80edcb57 100644
--- a/addons/stock/wizard/stock_location_product.py
+++ b/addons/stock/wizard/stock_location_product.py
@@ -28,8 +28,8 @@ class stock_location_product(osv.osv_memory):
_columns = {
'from_date': fields.datetime('From'),
'to_date': fields.datetime('To'),
- 'type': fields.selection([('inventory','Analyse Current Inventory'),
- ('period','Analyse a Period')], 'Analyse Type', required=True),
+ 'type': fields.selection([('inventory','Analyze current inventory'),
+ ('period','Analyze period')], 'Analysis Type', required=True),
}
def action_open_window(self, cr, uid, ids, context=None):
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 251f1977332..832faa4ca62 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1609,8 +1609,11 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
return facetValue.get('label');
},
make_domain: function (name, operator, facetValue) {
- if (operator === this.default_operator) {
+ switch(operator){
+ case this.default_operator:
return [[name, '=', facetValue.get('value')]];
+ case 'child_of':
+ return [[name, 'child_of', facetValue.get('value')]];
}
return this._super(name, operator, facetValue);
},
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 13a357a1d82..2a495c397e0 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -3471,7 +3471,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
self.display_value_backup = {};
self.render_value();
self.focus();
- self.view.do_onchange(self);
+ self.trigger('changed_value');
});
});
});
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index 324ae70f9e6..de31f13bd66 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -43,7 +43,7 @@
t-att-data-view-xmlid="xmlid if editable else None"
t-att-data-main-object="repr(main_object) if editable else None">
<head>
- <script type="text/javascript" src="/web/static/js/watch.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/watch.js"></script>
<t t-if="main_object and 'website_meta_title' in main_object">
<t t-set="title" t-value="main_object.website_meta_title"/>
</t>
diff --git a/addons/website_event_sale/views/website_event_sale.xml b/addons/website_event_sale/views/website_event_sale.xml
index 98f505581d3..f8f3436f17e 100644
--- a/addons/website_event_sale/views/website_event_sale.xml
+++ b/addons/website_event_sale/views/website_event_sale.xml
@@ -40,8 +40,9 @@
</tr>
</thead>
<tbody>
- <tr itemscope="itemscope" itemtype="http://data-vocabulary.org/Offer" t-foreach="event.event_ticket_ids" t-as="ticket">
- <td itemscope="itemscope" itemtype="http://data-vocabulary.org/Product">
+ <t t-foreach="event.event_ticket_ids" t-as="ticket">
+ <tr itemscope="itemscope" itemtype="http://data-vocabulary.org/Offer" t-if="not ticket.is_expired">
+ <td itemscope="itemscope" itemtype="http://data-vocabulary.org/Product">
<div itemprop="name" t-field="ticket.name"/>
<div><small itemprop="description" t-field="ticket.product_id.description_sale"/></div>
</td>
@@ -69,7 +70,8 @@
</select>
<span t-if="not ticket.seats_available">Sold Out</span>
</td>
- </tr>
+ </tr>
+ </t>
</tbody>
</table>
<button type="submit" class="btn btn-primary btn-lg pull-right" t-if="event.seats_available">Order Now</button>
diff --git a/addons/website_hr_recruitment/security/website_hr_recruitment_security.xml b/addons/website_hr_recruitment/security/website_hr_recruitment_security.xml
index 724c4dfddce..792995ca606 100644
--- a/addons/website_hr_recruitment/security/website_hr_recruitment_security.xml
+++ b/addons/website_hr_recruitment/security/website_hr_recruitment_security.xml
@@ -5,6 +5,7 @@
<field name="name">Job Positions: Public</field>
<field name="model_id" ref="hr.model_hr_job"/>
<field name="domain_force">[('website_published', '=', True)]</field>
+ <field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
@@ -14,6 +15,7 @@
<field name="name">Job department: Public</field>
<field name="model_id" ref="hr.model_hr_department"/>
<field name="domain_force">[('jobs_ids.website_published', '=', True)]</field>
+ <field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
diff --git a/addons/website_mail/views/snippets.xml b/addons/website_mail/views/snippets.xml
index b99be8f6d8c..98a79393211 100644
--- a/addons/website_mail/views/snippets.xml
+++ b/addons/website_mail/views/snippets.xml
@@ -428,7 +428,7 @@
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
- <a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
+ <a href="http://www.openerp.com" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>
@@ -445,7 +445,7 @@
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
- <a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
+ <a href="http://www.openerp.com" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>
@@ -462,7 +462,7 @@
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
- <a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
+ <a href="http://www.openerp.com" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>