From 9c0e8f10e0268c26cea1b991b0156f425a3c3e1a Mon Sep 17 00:00:00 2001
From: Simon Lejeune
Date: Mon, 13 Oct 2014 17:07:13 +0200
Subject: [PATCH 01/30] [FIX] sale: translate advance message on advance
invoice
---
addons/sale/wizard/sale_make_invoice_advance.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py
index 9c3160cb46a..c4798cc44d4 100644
--- a/addons/sale/wizard/sale_make_invoice_advance.py
+++ b/addons/sale/wizard/sale_make_invoice_advance.py
@@ -58,6 +58,9 @@ class sale_advance_payment_inv(osv.osv_memory):
'product_id': _get_advance_product,
}
+ def _translate_advance(self, cr, uid, percentage=False, context=None):
+ return _("Advance of %s %%") if percentage else _("Advance of %s %s")
+
def onchange_method(self, cr, uid, ids, advance_payment_method, product_id, context=None):
if advance_payment_method == 'percentage':
return {'value': {'amount':0, 'product_id':False }}
@@ -104,16 +107,17 @@ class sale_advance_payment_inv(osv.osv_memory):
if wizard.advance_payment_method == 'percentage':
inv_amount = sale.amount_total * wizard.amount / 100
if not res.get('name'):
- res['name'] = _("Advance of %s %%") % (wizard.amount)
+ res['name'] = self._translate_advance(cr, uid, percentage=True, context=dict(context, lang=sale.partner_id.lang)) % (wizard.amount)
else:
inv_amount = wizard.amount
if not res.get('name'):
#TODO: should find a way to call formatLang() from rml_parse
symbol = sale.pricelist_id.currency_id.symbol
if sale.pricelist_id.currency_id.position == 'after':
- res['name'] = _("Advance of %s %s") % (inv_amount, symbol)
+ symbol_order = (inv_amount, symbol)
else:
- res['name'] = _("Advance of %s %s") % (symbol, inv_amount)
+ symbol_order = (symbol, inv_amount)
+ res['name'] = self._translate_advance(cr, uid, context=dict(context, lang=sale.partner_id.lang)) % symbol_order
# determine taxes
if res.get('invoice_line_tax_id'):
@@ -159,7 +163,6 @@ class sale_advance_payment_inv(osv.osv_memory):
sale_obj.write(cr, uid, sale_id, {'invoice_ids': [(4, inv_id)]}, context=context)
return inv_id
-
def create_invoices(self, cr, uid, ids, context=None):
""" create invoices for the active sales orders """
sale_obj = self.pool.get('sale.order')
From 1d57a09112e4def7c7ed9cc010f9d683c18ac1ea Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Thu, 16 Oct 2014 14:07:38 +0200
Subject: [PATCH 02/30] [FIX] mail: set the parent_id to the first message of
type email
And fallback of any type if there is none of type email
This fix allow the communication between two mail thread from two different Odoo servers having message creation subtypes, like project issue or crm lead
---
addons/mail/mail_thread.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index ee039533af6..e82ed94c43b 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -1166,7 +1166,9 @@ class mail_thread(osv.AbstractModel):
# _mail_flat_thread: automatically set free messages to the first posted message
if self._mail_flat_thread and not parent_id and thread_id:
- message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1)
+ message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model), ('type', '=', 'email')], context=context, order="id ASC", limit=1)
+ if not message_ids:
+ message_ids = message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1)
parent_id = message_ids and message_ids[0] or False
# we want to set a parent: force to set the parent_id to the oldest ancestor, to avoid having more than 1 level of thread
elif parent_id:
From 639174bc53ffdb4503d240d3555e6bc5a725f994 Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Thu, 16 Oct 2014 18:38:20 +0200
Subject: [PATCH 03/30] [FIX] website: prevent editing contact address with
qweb contact widget
Because, currently, it copy the whole address in the contact name. The address is therefore duplicated
---
addons/website/models/ir_qweb.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py
index c598773c10b..f0a75dc31db 100644
--- a/addons/website/models/ir_qweb.py
+++ b/addons/website/models/ir_qweb.py
@@ -417,6 +417,9 @@ class Contact(orm.AbstractModel):
_name = 'website.qweb.field.contact'
_inherit = ['ir.qweb.field.contact', 'website.qweb.field.many2one']
+ def from_html(self, cr, uid, model, column, element, context=None):
+ return None
+
class QwebView(orm.AbstractModel):
_name = 'website.qweb.field.qweb'
_inherit = ['ir.qweb.field.qweb']
From bc38c36503339fa2bbac53369f1f3c4d390e3c7e Mon Sep 17 00:00:00 2001
From: Jeremy Kersten
Date: Thu, 16 Oct 2014 22:15:35 +0200
Subject: [PATCH 04/30] [FIX] website: fix snippet banner, else when a video is
dropped (using a div), the video is moved outside of the span col-md-6 by the
editor and so become invisble
---
addons/website/views/snippets.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml
index cee78689bda..84acc2346b5 100644
--- a/addons/website/views/snippets.xml
+++ b/addons/website/views/snippets.xml
@@ -34,9 +34,9 @@
Contact us
-
+

-
+
From dafa7958c6f3712fa3a5fc6b38405751882d4b96 Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Fri, 17 Oct 2014 10:58:06 +0200
Subject: [PATCH 05/30] [FIX] account: use float_compare instead of just <>
---
addons/account/account_cash_statement.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py
index d4c98b7c275..5b1952f44d9 100644
--- a/addons/account/account_cash_statement.py
+++ b/addons/account/account_cash_statement.py
@@ -23,6 +23,7 @@
import time
from openerp.osv import fields, osv
+from openerp.tools import float_compare
from openerp.tools.translate import _
import openerp.addons.decimal_precision as dp
@@ -80,7 +81,8 @@ class account_cash_statement(osv.osv):
if (statement.journal_id.type not in ('cash',)):
continue
if not statement.journal_id.cash_control:
- if statement.balance_end_real <> statement.balance_end:
+ prec = self.pool['decimal.precision'].precision_get(cr, uid, 'Account')
+ if float_compare(statement.balance_end_real, statement.balance_end, precision_digits=prec):
statement.write({'balance_end_real' : statement.balance_end})
continue
start = end = 0
From 85f1efac61161f56e948fe40646624174a9cf875 Mon Sep 17 00:00:00 2001
From: Josse Colpaert
Date: Thu, 16 Oct 2014 10:21:07 +0200
Subject: [PATCH 06/30] [FIX] Produce line should be connected to its
procurement
[FIX] Better to work through the production_id of the procurement
---
addons/mrp/mrp.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 837a2ab5a21..c239df0b3c5 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -1019,8 +1019,11 @@ class mrp_production(osv.osv):
def _make_production_produce_line(self, cr, uid, production, context=None):
stock_move = self.pool.get('stock.move')
+ proc_obj = self.pool.get('procurement.order')
source_location_id = production.product_id.property_stock_production.id
destination_location_id = production.location_dest_id.id
+ procs = proc_obj.search(cr, uid, [('production_id', '=', production.id)], context=context)
+ procurement_id = procs and procs[0] or False
data = {
'name': production.name,
'date': production.date_planned,
@@ -1032,6 +1035,7 @@ class mrp_production(osv.osv):
'location_id': source_location_id,
'location_dest_id': destination_location_id,
'move_dest_id': production.move_prod_id.id,
+ 'procurement_id': procurement_id,
'company_id': production.company_id.id,
'production_id': production.id,
'origin': production.name,
From d675f32ddae7b400b74216786c8a59e837c5d8d9 Mon Sep 17 00:00:00 2001
From: Josse Colpaert
Date: Fri, 17 Oct 2014 10:40:58 +0200
Subject: [PATCH 07/30] [FIX] Byproducts should not start in waiting state
---
addons/mrp_byproduct/mrp_byproduct.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/addons/mrp_byproduct/mrp_byproduct.py b/addons/mrp_byproduct/mrp_byproduct.py
index 5649604b57d..fa7c0784052 100644
--- a/addons/mrp_byproduct/mrp_byproduct.py
+++ b/addons/mrp_byproduct/mrp_byproduct.py
@@ -84,6 +84,7 @@ class mrp_production(osv.osv):
""" Confirms production order and calculates quantity based on subproduct_type.
@return: Newly generated picking Id.
"""
+ move_obj = self.pool.get('stock.move')
picking_id = super(mrp_production,self).action_confirm(cr, uid, ids, context=context)
product_uom_obj = self.pool.get('product.uom')
for production in self.browse(cr, uid, ids):
@@ -113,10 +114,11 @@ class mrp_production(osv.osv):
'location_id': source,
'location_dest_id': production.location_dest_id.id,
'move_dest_id': production.move_prod_id.id,
- 'state': 'waiting',
'production_id': production.id
}
- self.pool.get('stock.move').create(cr, uid, data)
+ move_id = move_obj.create(cr, uid, data, context=context)
+ move_obj.action_confirm(cr, uid, [move_id], context=context)
+
return picking_id
def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None):
From ba272ad69ae6745e91a42e4b5c9cbc7dc4fc1b0a Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Fri, 17 Oct 2014 14:47:26 +0200
Subject: [PATCH 08/30] [FIX] website_sale: no need to specific to a selection
field that it is of type char
Besides, if set, the field will appear as a simple char field in the form view & editable lists
+ADD the type in the editable view
---
addons/website_sale/models/product.py | 2 +-
addons/website_sale/views/views.xml | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py
index 2c0156fcfbc..1ce85d53c27 100644
--- a/addons/website_sale/models/product.py
+++ b/addons/website_sale/models/product.py
@@ -194,7 +194,7 @@ class product_product(osv.Model):
class product_attribute(osv.Model):
_inherit = "product.attribute"
_columns = {
- 'type': fields.selection([('radio', 'Radio'), ('select', 'Select'), ('color', 'Color'), ('hidden', 'Hidden')], string="Type", type="char"),
+ 'type': fields.selection([('radio', 'Radio'), ('select', 'Select'), ('color', 'Color'), ('hidden', 'Hidden')], string="Type"),
}
_defaults = {
'type': lambda *a: 'radio',
diff --git a/addons/website_sale/views/views.xml b/addons/website_sale/views/views.xml
index 9971097a061..239583d0195 100644
--- a/addons/website_sale/views/views.xml
+++ b/addons/website_sale/views/views.xml
@@ -55,6 +55,16 @@
+
+ product.attribute.tree.type
+ product.attribute
+
+
+
+
+
+
+
From 08f222d7079bc70aba4e2f248fd3978a8cda6087 Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Fri, 17 Oct 2014 15:29:00 +0200
Subject: [PATCH 09/30] [FIX] website: use dom element instead of jquery class
to click input file
For some reasons, the browser will prevent to open the system file browser when clicking the input file with javascript using the jquery class element, but it works when using the standard js dom element.
---
addons/website/static/src/js/website.editor.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index 2764e2138ee..a339ea6d63a 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -1379,11 +1379,17 @@
this.changed($(e.target));
},
'click button.filepicker': function () {
- this.$('input[type=file]').click();
+ var filepicker = this.$('input[type=file]');
+ if (!_.isEmpty(filepicker)){
+ filepicker[0].click();
+ }
},
'click .js_disable_optimization': function () {
this.$('input[name="disable_optimization"]').val('1');
- this.$('button.filepicker').click();
+ var filepicker = this.$('button.filepicker');
+ if (!_.isEmpty(filepicker)){
+ filepicker[0].click();
+ }
},
'change input[type=file]': 'file_selection',
'submit form': 'form_submit',
From 088f9e5b12e1b120d91246b5546ccaa1513e5cd5 Mon Sep 17 00:00:00 2001
From: Fabien Meghazi
Date: Fri, 17 Oct 2014 17:09:01 +0200
Subject: [PATCH 10/30] [FIX] Do not lose session.db on authentication error
---
openerp/addons/base/ir/ir_http.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py
index c490043716d..64e6636224e 100644
--- a/openerp/addons/base/ir/ir_http.py
+++ b/openerp/addons/base/ir/ir_http.py
@@ -85,7 +85,7 @@ class ir_http(osv.AbstractModel):
except (openerp.exceptions.AccessDenied, openerp.http.SessionExpiredException):
# All other exceptions mean undetermined status (e.g. connection pool full),
# let them bubble up
- request.session.logout()
+ request.session.logout(keep_db=True)
getattr(self, "_auth_method_%s" % auth_method)()
except (openerp.exceptions.AccessDenied, openerp.http.SessionExpiredException):
raise
From a6343387d756f53e3538992601e0680eded0caa3 Mon Sep 17 00:00:00 2001
From: Martin Trigaux
Date: Fri, 17 Oct 2014 14:22:13 +0200
Subject: [PATCH 11/30] [IMP] point_of_sale: add constraint on company
Using a payment method belonging to another company will raise errors when closing the session.
To avoid being stuck at session closing, forbid to create a POS using a journal of another company.
---
addons/point_of_sale/point_of_sale.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py
index 28b3795b0e0..87e4bf5ecb1 100644
--- a/addons/point_of_sale/point_of_sale.py
+++ b/addons/point_of_sale/point_of_sale.py
@@ -110,10 +110,21 @@ class pos_config(osv.osv):
return False
return True
+ def _check_company_payment(self, cr, uid, ids, context=None):
+ for config in self.browse(cr, uid, ids, context=context):
+ journal_ids = [j.id for j in config.journal_ids]
+ if self.pool['account.journal'].search(cr, uid, [
+ ('id', 'in', journal_ids),
+ ('company_id', '!=', config.company_id.id)
+ ], count=True, context=context):
+ return False
+ return True
+
_constraints = [
(_check_cash_control, "You cannot have two cash controls in one Point Of Sale !", ['journal_ids']),
(_check_company_location, "The company of the stock location is different than the one of point of sale", ['company_id', 'stock_location_id']),
(_check_company_journal, "The company of the sale journal is different than the one of point of sale", ['company_id', 'journal_id']),
+ (_check_company_payment, "The company of a payment method is different than the one of point of sale", ['company_id', 'journal_ids']),
]
def name_get(self, cr, uid, ids, context=None):
From ef4d8b2df037f86ad7da1e490fba2850db757171 Mon Sep 17 00:00:00 2001
From: kevin wang
Date: Fri, 17 Oct 2014 16:16:28 +0200
Subject: [PATCH 12/30] [FIX] mrp: traceability of production
When consuming product, the main_production_move is set as the source of production (used for consumed_for parameter)
However the method action_consume now (since 661a204) returns the new moves (when spliting) instead of the original one. This means that the tracebility would fail.
---
addons/mrp/mrp.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index c239df0b3c5..1791450d345 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -918,8 +918,8 @@ class mrp_production(osv.osv):
new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty_uom),
location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context)
stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context)
- if produce_product.product_id.id == production.product_id.id and new_moves:
- main_production_move = new_moves[0]
+ if produce_product.product_id.id == production.product_id.id:
+ main_production_move = produce_product.id
if production_mode in ['consume', 'consume_produce']:
if wiz:
From 289319816574c7ff8835e687c39f96c36323a633 Mon Sep 17 00:00:00 2001
From: Martin Trigaux
Date: Fri, 17 Oct 2014 16:31:30 +0200
Subject: [PATCH 13/30] [FIX] project: Overpassed Deadline computation
The field delay_endings_days represents the number of days since the deadline.
This field was using the write_date instead of now to compute it and was using the absolute value (so project in advance would also get overdue days
---
addons/project/report/project_report.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py
index e1e68050056..7bd8b827e01 100644
--- a/addons/project/report/project_report.py
+++ b/addons/project/report/project_report.py
@@ -87,7 +87,7 @@ class report_project_task_user(osv.osv):
planned_hours as hours_planned,
(extract('epoch' from (t.write_date-t.create_date)))/(3600*24) as closing_days,
(extract('epoch' from (t.date_start-t.create_date)))/(3600*24) as opening_days,
- abs((extract('epoch' from (t.date_deadline-t.write_date)))/(3600*24)) as delay_endings_days
+ (extract('epoch' from (t.date_deadline-now())))/(3600*24) as delay_endings_days
FROM project_task t
WHERE t.active = 'true'
GROUP BY
From 06de55649b69aea1501b968016f73c85e81c09e7 Mon Sep 17 00:00:00 2001
From: Josse Colpaert
Date: Fri, 17 Oct 2014 14:10:06 +0200
Subject: [PATCH 14/30] [FIX] Correct price correction courtesy of
richard_willowit #2983 #2985
---
addons/purchase/purchase.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index 9fe0238bb30..b87061696e4 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -701,7 +701,7 @@ class purchase_order(osv.osv):
product_uom = self.pool.get('product.uom')
price_unit = order_line.price_unit
if order_line.product_uom.id != order_line.product_id.uom_id.id:
- price_unit *= order_line.product_uom.factor
+ price_unit *= order_line.product_uom.factor / order_line.product_id.uom_id.factor
if order.currency_id.id != order.company_id.currency_id.id:
#we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context)
From 7cc3e65b33ca33eaeedb4c2dc8f3076cc963e414 Mon Sep 17 00:00:00 2001
From: dhr-odoo
Date: Tue, 14 Oct 2014 12:32:34 +0530
Subject: [PATCH 15/30] [FIX] account_followup: do no duplicate partner's
account.move.line
Duplicating a partner should not duplicate the content of the unreconciled_aml_ids field.
---
addons/account_followup/account_followup.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index f05d6fc2ab5..9cedbebf974 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -293,6 +293,13 @@ class res_partner(osv.osv):
model = 'res.partner', res_id = part.id,
partner_ids = [responsible_partner_id])
return super(res_partner, self).write(cr, uid, ids, vals, context=context)
+
+ def copy(self, cr, uid, record_id, default=None, context=None):
+ if default is None:
+ default = {}
+
+ default.update({'unreconciled_aml_ids': []})
+ return super(res_partner, self).copy(cr, uid, record_id, default, context)
def action_done(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'payment_next_action_date': False, 'payment_next_action':'', 'payment_responsible_id': False}, context=context)
From ed18ab7649dd441936025a46e5b8faa6a12defd5 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 20 Oct 2014 10:00:20 +0200
Subject: [PATCH 16/30] [ADD] doc: basic index page instead of something
completely blank
---
doc/_themes/odoodoc/layout.html | 2 +-
doc/conf.py | 4 ++++
doc/images/view-on-github.png | Bin 0 -> 1496 bytes
doc/index.rst | 32 ++++++++++++++++++++++++++++++--
doc/modules.rst | 1 -
doc/modules/mail.rst | 5 -----
6 files changed, 35 insertions(+), 9 deletions(-)
create mode 100644 doc/images/view-on-github.png
delete mode 100644 doc/modules/mail.rst
diff --git a/doc/_themes/odoodoc/layout.html b/doc/_themes/odoodoc/layout.html
index 3e75dadac89..1fcb690454e 100644
--- a/doc/_themes/odoodoc/layout.html
+++ b/doc/_themes/odoodoc/layout.html
@@ -35,7 +35,7 @@
main_navbar=False, titles_only=False) }}
{% if github_link %}
- Edit on GitHub
+ View on GitHub
{% endif %}
diff --git a/doc/conf.py b/doc/conf.py
index 169c6b64a61..9ae72b90928 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -20,6 +20,7 @@ needs_sphinx = '1.1'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
+ 'sphinx.ext.ifconfig',
'sphinx.ext.todo',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
@@ -165,6 +166,9 @@ html_sidebars = {
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
+# default must be set otherwise ifconfig blows up
+todo_include_todos = False
+
intersphinx_mapping = {
'python': ('https://docs.python.org/2/', None),
'werkzeug': ('http://werkzeug.pocoo.org/docs/', None),
diff --git a/doc/images/view-on-github.png b/doc/images/view-on-github.png
new file mode 100644
index 0000000000000000000000000000000000000000..afaabc400b8de21e0ffa574676f542ca83c09b63
GIT binary patch
literal 1496
zcmV;}1tE#qEfixqm!?j-ouZ!$83qFc*e1Co|>7Nov6n6`TD7yny9|unwzQJz^3-(
z#K__I!O-&S)VbjF{p;)M{rBAe|Mcwp|GK=q)X&+&rwsu|4qM_5%wiWG$3w`N
zG?UiB^CG3Ol?hlSi)_eoX0F3>ToXmv5CU^~78?&*LYl&X1zI1=OwxLW0im+$It*ou
zBG0*Hw;UKn2;^~p?dzl1mOYDggNRhU?4Be=H)8%~+jdPD8I`SQE?ISwP8?~!%hFSn
zSw@735N^6SA!iPsKQh9ic{^`Os+;!0ym_!$V~!i!YkDDvkE)YisaOoxxt*VF@NqqO
zd@9+_)q`d~r0TId^oUAGc<7AkcAgM5kAj0NizPfw35H@}0N$GoPU28z=@^kaH7%ME
z(5PL_gS1S}48`2#+}-{NWhsk0z2Ef}hiv^D=)=_2)z#J2)z#J2)irP1wqE9~vX|MQkg0wK&^<<%y;i$l*~3uZZfuzC8oTlap#
zP6I9%+cMp=UHtVwKO>(QsZs6khAN
ze3(rN3CBUWSVJ`U?2luOUPE#FZZAt^GNtI+!QfKsF5_<<_-KHM;Sh`a@sn&eNl3Dt
zJ>>afy0cAQDiAE$PDEu3XEQqJ^oCnC)u!Rv*Zy)JWngww1>gww1>gwwH)2_X(unogt0G2d6K7biHI_a|H{oiu3oP@%9(W@DT{*tDM
z81z*!rL;eqM{R#aZO|}kQ=8iUMbxG?wWZx5qTAE|XG;!i9OE`O0cUo7_cdVa5#tUp
zxECaV)s0Y|ryDSLZEQk|LW>2rp()*ZW6if?T#?-ADZoI>h8?U_R4Y9qYf>ZIjxptf
zA1UGv(9=>H`w3siipA0>Z^}notGPM0NtJC*SOTK%#OUKg$?n9niCNi6y&fbd9(M_4Ky-x0w07%X1AqnI*$uQ
z)AcLyO!=g+v+Crq4JR3zrEu_?<~EsGY1f*8rj#sY>{hCca%`ENrNwvmJ{s7zArW;m
zE%lz1Jhr;Vo7BSQpvH-fVLiPVF_UCrrRiC^09+n^UE6-ZGHaFX1Zbv+0%#b4@9>AHYpseAh
zkL*p_kS5u2AcT--3in8A$sAm}Y$3ndLhgxevZlp;0~ZfArFh?*E7td!Ul5r^wwD}m
z$tk?2DqFZEDkKG#ZUYqtR$I8qFUhG=pMqo{?by0000`_.
+Contributions are welcome and appreciated.
+
+.. todo:: what's the documentation's license?
+
+The documentation is currently organized in four sections:
+
+* :doc:`tutorials`, aimed at introducing the primary areas of developing Odoo
+ modules
+* :doc:`guides`, didactic documents covering more specific and specialized
+ areas of Odoo, trying to solve more specific problems
+* :doc:`reference`, which ought be the complete and canonical documentation
+ for Odoo subsystems
+* :doc:`modules`, documenting useful specialized modules and integration
+ methods (and currently empty)
.. hidden toctree w/o titlesonly otherwise the titlesonly "sticks" to
in-document toctrees and we can't have a toctree showing both "sibling"
@@ -16,4 +40,8 @@ odoo developer documentation
reference
modules
-.. todolist::
+.. ifconfig:: todo_include_todos
+
+ .. rubric:: Things to add and fix
+
+ .. todolist::
diff --git a/doc/modules.rst b/doc/modules.rst
index 7c90fcecdd7..16133d13413 100644
--- a/doc/modules.rst
+++ b/doc/modules.rst
@@ -5,4 +5,3 @@ Module Objects
.. toctree::
:titlesonly:
- modules/mail
diff --git a/doc/modules/mail.rst b/doc/modules/mail.rst
deleted file mode 100644
index 734feccb11f..00000000000
--- a/doc/modules/mail.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-============
-Mail Threads
-============
-
-
From 258a4cac82ef3b7e6a086f691f3bf8140d37b51c Mon Sep 17 00:00:00 2001
From: Simon Lejeune
Date: Fri, 17 Oct 2014 17:04:09 +0200
Subject: [PATCH 17/30] [FIX] website_sale: trigger the change event on the
right node
---
addons/website_sale/static/src/js/website_sale.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index 338369b46e3..e86897cc7d4 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -169,12 +169,15 @@ $('.oe_website_sale').each(function () {
$select.find("option:not(:first)").hide();
var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
$select.parent().toggle(nb>1);
- }).change();
+ });
+ $(oe_website_sale).find("select[name='country_id']").change();
+
$(oe_website_sale).on('change', "select[name='shipping_country_id']", function () {
var $select = $("select[name='shipping_state_id']");
$select.find("option:not(:first)").hide();
var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
$select.parent().toggle(nb>1);
- }).change();
+ });
+ $(oe_website_sale).find("select[name='shipping_country_id']").change();
});
});
From 69c133376629a5d3fb6d07c79f87d248ea49c1d1 Mon Sep 17 00:00:00 2001
From: rmu-odoo
Date: Thu, 16 Oct 2014 00:23:03 +0530
Subject: [PATCH 18/30] [FIX] l10n_fr_hr_payroll: report "Fiche de paye"
Avoids getting False for the field end_date (Sortie) in case of no end date specified on the contract. opw 614624
---
addons/l10n_fr_hr_payroll/report/fiche_paye.rml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
index 2d1a6bff8b2..801d445b275 100644
--- a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
+++ b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
@@ -244,7 +244,7 @@
[[o.contract_id.qualif or '_']]
[[o.contract_id.niveau or '_']]
[[o.contract_id.coef or '_']]
- [[o.contract_id.date_start or '_']] Sortie : [[o.contract_id.date_end or '']]
+ [[ formatLang(o.contract_id.date_end, date=True) or '_']] Sortie : [[ formatLang(o.contract_id.date_end, date=True) or '_']]
From b7d22d375cedf13e24ad6f1a2d4b3f852045ad8d Mon Sep 17 00:00:00 2001
From: Martin Trigaux
Date: Mon, 20 Oct 2014 10:48:19 +0200
Subject: [PATCH 19/30] [FIX] l10n_fr_hr_payroll: bad copy-paste in 69c1333
---
addons/l10n_fr_hr_payroll/report/fiche_paye.rml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
index 801d445b275..3cd5059770a 100644
--- a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
+++ b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
@@ -244,7 +244,7 @@
[[o.contract_id.qualif or '_']]
[[o.contract_id.niveau or '_']]
[[o.contract_id.coef or '_']]
- [[ formatLang(o.contract_id.date_end, date=True) or '_']] Sortie : [[ formatLang(o.contract_id.date_end, date=True) or '_']]
+ [[ formatLang(o.contract_id.date_start, date=True) or '_']] Sortie : [[ formatLang(o.contract_id.date_end, date=True) or '_']]
From f2401bc9054e59a89251bae4541594da90b432ee Mon Sep 17 00:00:00 2001
From: Arthur Maniet
Date: Fri, 3 Oct 2014 15:25:53 +0200
Subject: [PATCH 20/30] [FIX] account: bank statement reconciliation incorrect
rounding
---
addons/account/static/src/js/account_widgets.js | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js
index 158805fe55f..e80fb44a046 100644
--- a/addons/account/static/src/js/account_widgets.js
+++ b/addons/account/static/src/js/account_widgets.js
@@ -41,6 +41,7 @@ openerp.account = function (instance) {
this.max_move_lines_displayed = 5;
this.animation_speed = 100; // "Blocking" animations
this.aestetic_animation_speed = 300; // eye candy
+ this.map_currency_id_rounding = {};
this.map_tax_id_amount = {};
this.presets = {};
// We'll need to get the code of an account selected in a many2one (whose value is the id)
@@ -199,6 +200,13 @@ openerp.account = function (instance) {
_.each(data, function(o) { self.map_account_id_code[o.id] = o.code });
});
+ // Create a dict currency id -> rounding factor
+ new instance.web.Model("res.currency")
+ .query(['id', 'rounding'])
+ .all().then(function(data) {
+ _.each(data, function(o) { self.map_currency_id_rounding[o.id] = o.rounding });
+ });
+
// Create a dict tax id -> amount
new instance.web.Model("account.tax")
.query(['id', 'amount'])
@@ -639,6 +647,7 @@ openerp.account = function (instance) {
this.model_bank_statement_line = new instance.web.Model("account.bank.statement.line");
this.model_res_users = new instance.web.Model("res.users");
this.model_tax = new instance.web.Model("account.tax");
+ this.map_currency_id_rounding = this.getParent().map_currency_id_rounding;
this.map_account_id_code = this.getParent().map_account_id_code;
this.map_tax_id_amount = this.getParent().map_tax_id_amount;
this.presets = this.getParent().presets;
@@ -1406,7 +1415,6 @@ openerp.account = function (instance) {
}
);
} else {
- line_created_being_edited[0].amount = amount;
line_created_being_edited.length = 1;
deferred_tax.resolve();
}
@@ -1414,9 +1422,12 @@ openerp.account = function (instance) {
$.when(deferred_tax).then(function(){
// Format amounts
+ var rounding = 1/self.map_currency_id_rounding[self.st_line.currency_id];
$.each(line_created_being_edited, function(index, val) {
- if (val.amount)
+ if (val.amount) {
+ line_created_being_edited[index].amount = Math.round(val.amount*rounding)/rounding;
line_created_being_edited[index].amount_str = self.formatCurrency(Math.abs(val.amount), val.currency_id);
+ }
});
self.set("line_created_being_edited", line_created_being_edited);
self.createdLinesChanged(); // TODO For some reason, previous line doesn't trigger change handler
From 40acb7ee6ca77eda038f4bb445c181e010e5e533 Mon Sep 17 00:00:00 2001
From: Arthur Maniet
Date: Fri, 19 Sep 2014 16:25:18 +0200
Subject: [PATCH 21/30] [IMP] account: reconciliation widget: load list of move
lines in a single RPC call with limit set. It drastically improves
performances on big databases. [FIX] account: reconciliation widget: for
reconciliations with no partner, allow to select move lines from any partner
and apply global move lines exclusion.
---
.../account/static/src/js/account_widgets.js | 68 ++++++++-----------
1 file changed, 30 insertions(+), 38 deletions(-)
diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js
index e80fb44a046..04189e36d7f 100644
--- a/addons/account/static/src/js/account_widgets.js
+++ b/addons/account/static/src/js/account_widgets.js
@@ -355,10 +355,12 @@ openerp.account = function (instance) {
self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed);
});
});
- }
- // Congratulate the user if the work is done
- if (self.reconciled_lines === self.st_lines.length) {
+ } else if (self.reconciled_lines === self.st_lines.length) {
+ // Congratulate the user if the work is done
self.displayDoneMessage();
+ } else {
+ // Some lines weren't persisted because they were't valid
+ self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed);
}
}).fail(function() {
self.$(".reconciliation_lines_container").fadeIn(self.aestetic_animation_speed);
@@ -394,7 +396,7 @@ openerp.account = function (instance) {
// Update children if needed
_.each(self.getChildren(), function(child){
- if (child.partner_id === partner_id && child !== source_child) {
+ if ((child.partner_id === partner_id || child.st_line.has_no_partner) && child !== source_child) {
if (contains_lines(child.get("mv_lines_selected"), line_ids)) {
child.set("mv_lines_selected", _.filter(child.get("mv_lines_selected"), function(o){ return line_ids.indexOf(o.id) === -1 }));
} else if (contains_lines(child.mv_lines_deselected, line_ids)) {
@@ -420,6 +422,8 @@ openerp.account = function (instance) {
_.each(self.getChildren(), function(child){
if (child.partner_id === partner_id && child !== source_child && (child.get("mode") === "match" || child.$el.hasClass("no_match")))
child.updateMatches();
+ if (child.st_line.has_no_partner && child.get("mode") === "match" || child.$el.hasClass("no_match"))
+ child.updateMatches();
});
},
@@ -653,7 +657,7 @@ openerp.account = function (instance) {
this.presets = this.getParent().presets;
this.is_valid = true;
this.is_consistent = true; // Used to prevent bad server requests
- this.total_move_lines_num = undefined; // Used for pagers
+ this.can_fetch_more_move_lines; // Tell if we can show more move lines
this.filter = "";
// In rare cases like when deleting a statement line's partner we don't want the server to
// look for a reconciliation proposition (in this particular case it might find a move line
@@ -1048,16 +1052,15 @@ openerp.account = function (instance) {
pagerControlLeftHandler: function() {
var self = this;
if (self.$(".pager_control_left").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ }
- if (self.total_move_lines_num < 0) { return; }
+ if (self.get("pager_index") === 0) { return; }
self.set("pager_index", self.get("pager_index")-1 );
},
pagerControlRightHandler: function() {
var self = this;
- var new_index = self.get("pager_index")+1;
if (self.$(".pager_control_right").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ }
- if ((new_index * self.max_move_lines_displayed) >= self.total_move_lines_num) { return; }
- self.set("pager_index", new_index );
+ if (! self.can_fetch_more_move_lines) { return; }
+ self.set("pager_index", self.get("pager_index")+1 );
},
filterHandler: function() {
@@ -1231,7 +1234,7 @@ openerp.account = function (instance) {
self.$(".pager_control_left").addClass("disabled");
else
self.$(".pager_control_left").removeClass("disabled");
- if (self.total_move_lines_num <= ((self.get("pager_index")+1) * self.max_move_lines_displayed))
+ if (! self.can_fetch_more_move_lines)
self.$(".pager_control_right").addClass("disabled");
else
self.$(".pager_control_right").removeClass("disabled");
@@ -1332,12 +1335,12 @@ openerp.account = function (instance) {
mvLinesChanged: function() {
var self = this;
// If pager_index is out of range, set it to display the last page
- if (self.get("pager_index") !== 0 && self.total_move_lines_num <= (self.get("pager_index") * self.max_move_lines_displayed)) {
- self.set("pager_index", Math.ceil(self.total_move_lines_num/self.max_move_lines_displayed)-1);
+ if (self.get("pager_index") !== 0 && self.get("mv_lines").length === 0 && ! self.can_fetch_more_move_lines) {
+ self.set("pager_index", 0);
}
// If there is no match to display, disable match view and pass in mode inactive
- if (self.total_move_lines_num + self.mv_lines_deselected.length === 0 && self.filter === "") {
+ if (self.get("mv_lines").length + self.mv_lines_deselected.length === 0 && !self.can_fetch_more_move_lines && self.filter === "") {
self.$el.addClass("no_match");
if (self.get("mode") === "match") {
self.set("mode", "inactive");
@@ -1545,48 +1548,38 @@ openerp.account = function (instance) {
updateMatches: function() {
var self = this;
var deselected_lines_num = self.mv_lines_deselected.length;
- var move_lines_num = 0;
var offset = self.get("pager_index") * self.max_move_lines_displayed - deselected_lines_num;
if (offset < 0) offset = 0;
var limit = (self.get("pager_index")+1) * self.max_move_lines_displayed - deselected_lines_num;
if (limit > self.max_move_lines_displayed) limit = self.max_move_lines_displayed;
- var excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id];
var excluded_ids = _.collect(self.get("mv_lines_selected").concat(self.mv_lines_deselected), function(o) { return o.id; });
- var globally_excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id];
+ var globally_excluded_ids = [];
+ if (self.st_line.has_no_partner)
+ _.each(self.getParent().excluded_move_lines_ids, function(o) { globally_excluded_ids = globally_excluded_ids.concat(o) });
+ else
+ globally_excluded_ids = self.getParent().excluded_move_lines_ids[self.partner_id];
if (globally_excluded_ids !== undefined)
for (var i=0; i 0) {
- // Load move lines
- deferred_move_lines = self.model_bank_statement_line
+ return self.model_bank_statement_line
.call("get_move_lines_for_reconciliation_by_statement_line_id", [self.st_line.id, excluded_ids, self.filter, offset, limit])
.then(function (lines) {
- _.each(lines, function(line) {
- self.decorateMoveLine(line, self.st_line.currency_id);
- move_lines.push(line);
- }, self);
+ _.each(lines, function(line) { self.decorateMoveLine(line, self.st_line.currency_id) }, self);
+ // If we could fetch 1 more item than what we'll display, that means there are move lines left to be displayed (so we enable the pager)
+ self.can_fetch_more_move_lines = (lines.length === limit);
+ self.set("mv_lines", lines.slice(0, limit-1));
});
+ } else {
+ self.set("mv_lines", []);
}
-
- // Fetch the number of move lines corresponding to this statement line and this filter
- var deferred_total_move_lines_num = self.model_bank_statement_line
- .call("get_move_lines_for_reconciliation_by_statement_line_id", [self.st_line.id, excluded_ids, self.filter, 0, undefined, true])
- .then(function(num){
- move_lines_num = num;
- });
-
- return $.when(deferred_move_lines, deferred_total_move_lines_num).then(function(){
- self.total_move_lines_num = move_lines_num + deselected_lines_num;
- self.set("mv_lines", move_lines);
- });
},
// Changes the partner_id of the statement_line in the DB and reloads the widget
- changePartner: function(partner_id, callback) {
+ changePartner: function(partner_id) {
var self = this;
self.is_consistent = false;
return self.model_bank_statement_line
@@ -1599,7 +1592,6 @@ openerp.account = function (instance) {
self.do_load_reconciliation_proposition = true;
self.is_consistent = true;
self.set("mode", "match");
- if (callback) callback();
});
});
},
From 6c61d3c800d84e00f54aa6bc9312ddeba4190bab Mon Sep 17 00:00:00 2001
From: Arthur Maniet
Date: Tue, 23 Sep 2014 11:47:34 +0200
Subject: [PATCH 22/30] [FIX] account: the partner of a bank account can only
be a company or an individual not related to a company
---
openerp/addons/base/res/res_bank.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py
index 84529f0080a..91ede733416 100644
--- a/openerp/addons/base/res/res_bank.py
+++ b/openerp/addons/base/res/res_bank.py
@@ -128,7 +128,7 @@ class res_partner_bank(osv.osv):
change_default=True, domain="[('country_id','=',country_id)]"),
'company_id': fields.many2one('res.company', 'Company',
ondelete='cascade', help="Only if this bank account belong to your company"),
- 'partner_id': fields.many2one('res.partner', 'Account Owner', ondelete='cascade', select=True),
+ 'partner_id': fields.many2one('res.partner', 'Account Owner', ondelete='cascade', select=True, domain=['|',('is_company','=',True),('parent_id','=',False)]),
'state': fields.selection(_bank_type_get, 'Bank Account Type', required=True,
change_default=True),
'sequence': fields.integer('Sequence'),
From b00122ad995c1f0b80bf30dcd46580bef2422743 Mon Sep 17 00:00:00 2001
From: Julien Legros
Date: Mon, 20 Oct 2014 15:41:52 +0200
Subject: [PATCH 23/30] [FIX] res_partner: add parent_name related field
In some cases (e.g. with record rules), the name_get might not have access
to the parent name. Therefore a parent_name related field solves the
issue (as it read with as superuser).
---
openerp/addons/base/res/res_partner.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py
index 2d52b980780..22cd4a8d66a 100644
--- a/openerp/addons/base/res/res_partner.py
+++ b/openerp/addons/base/res/res_partner.py
@@ -218,6 +218,7 @@ class res_partner(osv.osv, format_address):
'date': fields.date('Date', select=1),
'title': fields.many2one('res.partner.title', 'Title'),
'parent_id': fields.many2one('res.partner', 'Related Company', select=True),
+ 'parent_name': fields.related('parent_id', 'name', type='char', readonly=True, string='Parent name'),
'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override
'ref': fields.char('Reference', size=64, select=1),
'lang': fields.selection(_lang_get, 'Language',
@@ -561,7 +562,7 @@ class res_partner(osv.osv, format_address):
for record in self.browse(cr, uid, ids, context=context):
name = record.name
if record.parent_id and not record.is_company:
- name = "%s, %s" % (record.parent_id.name, name)
+ name = "%s, %s" % (record.parent_name, name)
if context.get('show_address'):
name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context)
name = name.replace('\n\n','\n')
@@ -776,7 +777,7 @@ class res_partner(osv.osv, format_address):
'state_name': address.state_id and address.state_id.name or '',
'country_code': address.country_id and address.country_id.code or '',
'country_name': address.country_id and address.country_id.name or '',
- 'company_name': address.parent_id and address.parent_id.name or '',
+ 'company_name': address.parent_id and address.parent_name or '',
}
for field in self._address_fields(cr, uid, context=context):
args[field] = getattr(address, field) or ''
From 32f8a18dbfa87a6d12ea6062708bef119996c2d8 Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Mon, 20 Oct 2014 17:06:30 +0200
Subject: [PATCH 24/30] [FIX] auth_signup: refresh is no longer needed with the
new api
Besides, it leads to a invalidation of the cache, which is not needed here.
---
addons/auth_signup/res_users.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py
index 97bcea52bc1..620298c72d5 100644
--- a/addons/auth_signup/res_users.py
+++ b/addons/auth_signup/res_users.py
@@ -64,7 +64,6 @@ class res_partner(osv.Model):
# when required, make sure the partner has a valid signup token
if context.get('signup_valid') and not partner.user_ids:
self.signup_prepare(cr, uid, [partner.id], context=context)
- partner.refresh()
route = 'login'
# the parameters to encode for the query
From 285ba3d801507a937d65422e14dab46cd7b681aa Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Mon, 20 Oct 2014 17:50:22 +0200
Subject: [PATCH 25/30] [FIX] account: default product taxes on
product.template
As product.template is now most commonly used than product.product
This is related to fix 96dd8bf
---
addons/account/res_config.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/addons/account/res_config.py b/addons/account/res_config.py
index 8e9679eb74c..3f3e1563b14 100644
--- a/addons/account/res_config.py
+++ b/addons/account/res_config.py
@@ -235,8 +235,8 @@ class account_config_settings(osv.osv_memory):
})
# update taxes
ir_values = self.pool.get('ir.values')
- taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id)
- supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id)
+ taxes_id = ir_values.get_default(cr, uid, 'product.template', 'taxes_id', company_id=company_id)
+ supplier_taxes_id = ir_values.get_default(cr, uid, 'product.template', 'supplier_taxes_id', company_id=company_id)
values.update({
'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id,
'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id,
@@ -305,9 +305,9 @@ class account_config_settings(osv.osv_memory):
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
ir_values = self.pool.get('ir.values')
config = self.browse(cr, uid, ids[0], context)
- ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'taxes_id',
+ ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'taxes_id',
config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id)
- ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'supplier_taxes_id',
+ ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'supplier_taxes_id',
config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id)
def set_chart_of_accounts(self, cr, uid, ids, context=None):
From bfb61cd5e97ad1e710c5f65c42261be8657c285b Mon Sep 17 00:00:00 2001
From: Denis Ledoux
Date: Mon, 20 Oct 2014 18:40:06 +0200
Subject: [PATCH 26/30] [FIX] website_sale: image doesn't change when the user
select a product (for product variant list). website_sale_options: image
dones't change in modal with the selection
---
addons/website_sale/static/src/js/website_sale.js | 5 ++++-
addons/website_sale_options/static/src/js/website_sale.js | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index e86897cc7d4..34cf1fce863 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -94,6 +94,9 @@ $('.oe_website_sale').each(function () {
var $parent = $(this).closest('.js_product');
$parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) );
$parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) );
+
+ var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img, img.product_detail_img');
+ $img.attr("src", "/website/image/product.product/" + $(this).val() + "/image");
});
$(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change', function (ev) {
@@ -126,7 +129,7 @@ $('.oe_website_sale').each(function () {
}
if (product_id) {
- var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img');
+ var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img, img.product_detail_img');
$img.attr("src", "/website/image/product.product/" + product_id + "/image");
$img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
.data('oe-model', 'product.product').data('oe-id', product_id);
diff --git a/addons/website_sale_options/static/src/js/website_sale.js b/addons/website_sale_options/static/src/js/website_sale.js
index c0dba9eed10..72a45139b83 100644
--- a/addons/website_sale_options/static/src/js/website_sale.js
+++ b/addons/website_sale_options/static/src/js/website_sale.js
@@ -5,15 +5,18 @@ $(document).ready(function () {
.click(function (event) {
var $form = $(this).closest('form');
var quantity = parseFloat($form.find('input[name="add_qty"]').val() || 1);
+ var product_id = parseInt($form.find('input[type="hidden"][name="product_id"], input[type="radio"][name="product_id"]:checked').first().val(),10);
event.preventDefault();
openerp.jsonRpc("/shop/modal", 'call', {
- 'product_id': parseInt($form.find('input[name="product_id"]').val(),10),
+ 'product_id': product_id,
kwargs: {
context: openerp.website.get_context()
},
}).then(function (modal) {
var $modal = $(modal);
+ $modal.find('img:first').attr("src", "/website/image/product.product/" + product_id + "/image");
+
$modal.appendTo($form)
.modal()
.on('hidden.bs.modal', function () {
From edc4b0b9bb87aeae2e923a5a0d93e12ee171906d Mon Sep 17 00:00:00 2001
From: Christophe Simonis
Date: Mon, 20 Oct 2014 20:14:36 +0200
Subject: [PATCH 27/30] [FIX] {web,point_of_sale}: allow cross-origin access to
company logo
---
addons/point_of_sale/static/src/js/models.js | 5 +++--
addons/web/controllers/main.py | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
index 66b9d67eeaa..17eb0f69bd5 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -276,18 +276,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
c.height = height
var ctx = c.getContext('2d');
ctx.drawImage(self.company_logo,0,0, width, height);
-
+
self.company_logo_base64 = c.toDataURL();
logo_loaded.resolve();
};
self.company_logo.onerror = function(){
logo_loaded.reject();
};
+ self.company_logo.crossOrigin = "anonymous";
self.company_logo.src = '/web/binary/company_logo'+'?_'+Math.random();
return logo_loaded;
});
-
+
return loaded;
},
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index b59e01b6c39..295783dd384 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -1471,7 +1471,7 @@ class Binary(http.Controller):
'/web/binary/company_logo',
'/logo',
'/logo.png',
- ], type='http', auth="none")
+ ], type='http', auth="none", cors="*")
def company_logo(self, dbname=None, **kw):
# TODO add etag, refactor to use /image code for etag
uid = None
From b9953acb0f3221bb66cd78afbd0d7949cf48161c Mon Sep 17 00:00:00 2001
From: Olivier Dony
Date: Tue, 21 Oct 2014 01:19:05 +0200
Subject: [PATCH 28/30] [FIX] website_forum: respect karma when posting
questions/answers/comments + more user-friendly errors
While posting new questions and answers the check
for karma limit was bypassed because it was using
super-user mode: use regular user instead.
Also improve the user feedback when karma level is
too low to perform some actions: post comment,
post question, post answer.
The usability in these cases still needs to be
improved.
---
addons/website_forum/controllers/main.py | 8 +++-----
addons/website_forum/models/forum.py | 18 ++++++++++++++----
addons/website_forum/views/website_forum.xml | 15 ++++++++++-----
3 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index ea68250b986..08e03d9d6bf 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -298,12 +298,10 @@ class WebsiteForum(http.Controller):
cr, uid, context = request.cr, request.uid, request.context
if kwargs.get('comment') and post.forum_id.id == forum.id:
# TDE FIXME: check that post_id is the question or one of its answers
- request.registry['forum.post'].message_post(
- cr, uid, post.id,
+ request.registry['forum.post']._post_comment(
+ cr, uid, post,
body=kwargs.get('comment'),
- type='comment',
- subtype='mt_comment',
- context=dict(context, mail_create_nosubcribe=True))
+ context=context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum//post//toggle_correct', type='json', auth="public", website=True)
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index b39298a5921..1bc9b69b37a 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -10,8 +10,9 @@ from openerp.osv import osv, fields
from openerp.tools import html2plaintext
from openerp.tools.translate import _
+from werkzeug.exceptions import Forbidden
-class KarmaError(ValueError):
+class KarmaError(Forbidden):
""" Karma-related error, used for forum and posts. """
pass
@@ -314,11 +315,11 @@ class Post(osv.Model):
context = {}
create_context = dict(context, mail_create_nolog=True)
post_id = super(Post, self).create(cr, uid, vals, context=create_context)
- post = self.browse(cr, SUPERUSER_ID, post_id, context=context) # SUPERUSER_ID to avoid read access rights issues when creating
+ post = self.browse(cr, uid, post_id, context=context)
# karma-based access
- if post.parent_id and not post.can_ask:
+ if not post.parent_id and not post.can_ask:
raise KarmaError('Not enough karma to create a new question')
- elif not post.parent_id and not post.can_answer:
+ elif post.parent_id and not post.can_answer:
raise KarmaError('Not enough karma to answer to a question')
# messaging and chatter
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
@@ -508,6 +509,15 @@ class Post(osv.Model):
res_id = post.parent_id and "%s#answer-%s" % (post.parent_id.id, post.id) or post.id
return "/forum/%s/question/%s" % (post.forum_id.id, res_id)
+ def _post_comment(self, cr, uid, post, body, context=None):
+ context = dict(context or {}, mail_create_nosubcribe=True)
+ if not post.can_comment:
+ raise KarmaError('Not enough karma to comment')
+ return self.message_post(cr, uid, post.id,
+ body=body,
+ type='comment',
+ subtype='mt_comment',
+ context=context)
class PostReason(osv.Model):
_name = "forum.post.reason"
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index 9f1ef5159c2..9fbd27ef793 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -99,7 +99,10 @@