Skip to content

Commit

Permalink
[MERGE] forward port branch saas-15 up to d44cd77
Browse files Browse the repository at this point in the history
  • Loading branch information
KangOl committed Jun 12, 2018
2 parents 9205238 + d44cd77 commit e3658d6
Show file tree
Hide file tree
Showing 28 changed files with 147 additions and 27 deletions.
11 changes: 9 additions & 2 deletions addons/account/models/account_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,13 @@ def get_invoice_line_account(self, type, product, fpos, company):
return accounts['income']
return accounts['expense']

def _set_currency(self):
company = self.invoice_id.company_id
currency = self.invoice_id.currency_id
if company and currency:
if company.currency_id != currency:
self.price_unit = self.price_unit * currency.with_context(dict(self._context or {}, date=self.invoice_id.date_invoice)).rate

def _set_taxes(self):
""" Used in on_change to set taxes and price."""
if self.invoice_id.type in ('out_invoice', 'out_refund'):
Expand All @@ -1525,8 +1532,10 @@ def _set_taxes(self):
prec = self.env['decimal.precision'].precision_get('Product Price')
if not self.price_unit or float_compare(self.price_unit, self.product_id.standard_price, precision_digits=prec) == 0:
self.price_unit = fix_price(self.product_id.standard_price, taxes, fp_taxes)
self._set_currency()
else:
self.price_unit = fix_price(self.product_id.lst_price, taxes, fp_taxes)
self._set_currency()

@api.onchange('product_id')
def _onchange_product_id(self):
Expand Down Expand Up @@ -1575,8 +1584,6 @@ def _onchange_product_id(self):
domain['uom_id'] = [('category_id', '=', product.uom_id.category_id.id)]

if company and currency:
if company.currency_id != currency:
self.price_unit = self.price_unit * currency.with_context(dict(self._context or {}, date=self.invoice_id.date_invoice)).rate

if self.uom_id and self.uom_id.id != product.uom_id.id:
self.price_unit = product.uom_id._compute_price(self.price_unit, self.uom_id)
Expand Down
2 changes: 1 addition & 1 deletion addons/account/models/res_config_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ResConfigSettings(models.TransientModel):
'account.journal',
related='company_id.currency_exchange_journal_id',
string="Exchange Gain or Loss Journal",
domain=[('type', '=', 'general')],
domain="[('company_id', '=', company_id), ('type', '=', 'general')]",
help='The accounting journal where automatic exchange differences will be registered')
has_chart_of_accounts = fields.Boolean(compute='_compute_has_chart_of_accounts', string='Company has a chart of accounts')
chart_template_id = fields.Many2one('account.chart.template', string='Template',
Expand Down
16 changes: 9 additions & 7 deletions addons/account/views/account_journal_dashboard_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,16 @@
<span><t t-esc="dashboard.account_balance"/></span>
</div>
</div>
<div class="row" name="latest_statement" t-if="dashboard.last_balance != dashboard.account_balance">
<div class="col-xs-6">
<span title="Latest Statement">Latest Statement</span>
</div>
<div class="col-xs-6 text-right">
<span><t t-esc="dashboard.last_balance"/></span>
<t t-if="dashboard.last_balance != dashboard.account_balance">
<div class="row" name="latest_statement">
<div class="col-xs-6">
<span title="Latest Statement">Latest Statement</span>
</div>
<div class="col-xs-6 text-right">
<span><t t-esc="dashboard.last_balance"/></span>
</div>
</div>
</div>
</t>
</div>
</t>
<t t-name="JournalBodySalePurchase" id="account.JournalBodySalePurchase">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ def import_file(self):
# Create the bank statements
statement_ids, notifications = self._create_bank_statements(stmts_vals)
# Now that the import worked out, set it as the bank_statements_source of the journal
journal.bank_statements_source = 'file_import'
if journal.bank_statements_source != 'file_import':
# Use sudo() because only 'account.group_account_manager'
# has write access on 'account.journal', but 'account.group_account_user'
# must be able to import bank statement files
journal.sudo().bank_statements_source = 'file_import'
# Finally dispatch to reconciliation interface
action = self.env.ref('account.action_bank_reconcile_bank_statements')
return {
Expand Down
2 changes: 1 addition & 1 deletion addons/event/models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ResPartner(models.Model):

def _compute_event_count(self):
for partner in self:
partner.event_count = self.env['event.event'].search_count([('registration_ids.partner_id', 'child_of', partner.ids)])
partner.event_count = self.env['event.event'].sudo().search_count([('registration_ids.partner_id', 'child_of', partner.ids)])

@api.multi
def action_event_view(self):
Expand Down
2 changes: 2 additions & 0 deletions addons/mrp/models/mrp_bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ def onchange_product_uom_id(self):
def onchange_product_tmpl_id(self):
if self.product_tmpl_id:
self.product_uom_id = self.product_tmpl_id.uom_id.id
if self.product_id.product_tmpl_id != self.product_tmpl_id:
self.product_id = False

@api.onchange('routing_id')
def onchange_routing_id(self):
Expand Down
1 change: 1 addition & 0 deletions addons/mrp/models/mrp_workorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ def record_production(self):
move_line = production_move.move_line_ids.filtered(lambda x: x.lot_id.id == self.final_lot_id.id)
if move_line:
move_line.product_uom_qty += self.qty_producing
move_line.qty_done += self.qty_producing
else:
move_line.create({'move_id': production_move.id,
'product_id': production_move.product_id.id,
Expand Down
2 changes: 1 addition & 1 deletion addons/mrp/views/mrp_workorder_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
<label for="duration"/>
<div>
<button style="pointer-events: none;" class="oe_inline label label-default">
<field name="duration" widget="mrp_time_counter"/>
<field name="duration" widget="mrp_time_counter" help="Time the currently logged user spent on this workorder."/>
</button>
</div>
</group>
Expand Down
4 changes: 2 additions & 2 deletions addons/point_of_sale/models/pos_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def _confirm_orders(self):
paid=order.amount_paid,
))
order.action_pos_order_done()
orders = session.order_ids.filtered(lambda order: order.state in ['invoiced', 'done'])
orders.sudo()._reconcile_payments()
orders_to_reconcile = session.order_ids.filtered(lambda order: order.state in ['invoiced', 'done'] and order.partner_id)
orders_to_reconcile.sudo()._reconcile_payments()

config_id = fields.Many2one(
'pos.config', string='Point of Sale',
Expand Down
2 changes: 1 addition & 1 deletion addons/portal/wizard/portal_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def action_apply(self):
if wizard_user.partner_id.company_id:
company_id = wizard_user.partner_id.company_id.id
else:
company_id = self.env['res.company']._company_default_get('res.users')
company_id = self.env['res.company']._company_default_get('res.users').id
user_portal = wizard_user.sudo().with_context(company_id=company_id)._create_user()
else:
user_portal = user
Expand Down
2 changes: 2 additions & 0 deletions addons/product/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ def _compute_product_code(self):
for supplier_info in self.seller_ids:
if supplier_info.name.id == self._context.get('partner_id'):
self.code = supplier_info.product_code or self.default_code
break
else:
self.code = self.default_code

Expand All @@ -230,6 +231,7 @@ def _compute_partner_ref(self):
for supplier_info in self.seller_ids:
if supplier_info.name.id == self._context.get('partner_id'):
product_name = supplier_info.product_name or self.default_code
break
self.partner_ref = '%s%s' % (self.code and '[%s] ' % self.code or '', product_name)
else:
self.partner_ref = self.name_get()[0][1]
Expand Down
2 changes: 1 addition & 1 deletion addons/product/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import test_variants, test_uom, test_pricelist, test_product_pricelist
from . import test_seller, test_variants, test_uom, test_pricelist, test_product_pricelist
28 changes: 28 additions & 0 deletions addons/product/tests/test_seller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.tests.common import TransactionCase


class TestSeller(TransactionCase):

def setUp(self):
super(TestSeller, self).setUp()
self.product_service = self.env.ref('product.product_product_2')
self.product_service.default_code = 'DEFCODE'
self.asustec = self.env.ref('base.res_partner_1')
self.camptocamp = self.env.ref('base.res_partner_12')

def test_10_sellers(self):
self.product_service.write({'seller_ids': [
(0, 0, {'name': self.asustec.id, 'product_code': 'ASUCODE'}),
(0, 0, {'name': self.camptocamp.id, 'product_code': 'C2CCODE'}),
]})

default_code = self.product_service.code
self.assertEqual("DEFCODE", default_code, "Default code not used in product name")

context_code = self.product_service\
.with_context(partner_id=self.camptocamp.id)\
.code
self.assertEqual('C2CCODE', context_code, "Partner's code not used in product name with context set")
2 changes: 1 addition & 1 deletion addons/project/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ def _notification_recipients(self, message, groups):

groups = [new_group] + groups
for group_name, group_method, group_data in groups:
if group_name in ['customer', 'portal']:
if group_name == 'customer':
continue
group_data['has_button_access'] = True

Expand Down
4 changes: 4 additions & 0 deletions addons/website_event/static/src/js/website_event.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ var EventRegistrationForm = Widget.extend({
$button.attr('disabled', true);
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
var $modal = $(modal);
$modal.modal({backdrop: 'static', keyboard: false});
$modal.find('.modal-body > div').removeClass('container'); // retrocompatibility - REMOVE ME in master / saas-19
$modal.insertAfter($form).modal();
$modal.on('click', '.js_goto_event', function () {
$modal.modal('hide');
$button.prop('disabled', false);
});
$modal.on('click', '.close', function () {
$button.prop('disabled', false);
});
});
}
},
Expand Down
5 changes: 5 additions & 0 deletions addons/website_forum/models/forum.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ def _update_content(self, content, forum_id):
raise KarmaError('User karma not sufficient to post an image or link.')
return content

@api.constrains('parent_id')
def _check_parent_id(self):
if not self._check_recursion():
raise ValidationError(_('You cannot create recursive forum posts.'))

@api.model
def create(self, vals):
if 'content' in vals and vals.get('forum_id'):
Expand Down
10 changes: 7 additions & 3 deletions addons/website_livechat/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ def channel_list(self, **kw):
@http.route('/livechat/channel/<model("im_livechat.channel"):channel>', type='http', auth='public', website=True)
def channel_rating(self, channel, **kw):
# get the last 100 ratings and the repartition per grade
ratings = request.env['rating.rating'].search([('res_model', '=', 'mail.channel'), ('res_id', 'in', channel.sudo().channel_ids.ids)], order='create_date desc', limit=100)
repartition = channel.sudo().channel_ids.rating_get_grades()
domain = [
('res_model', '=', 'mail.channel'), ('res_id', 'in', channel.sudo().channel_ids.ids),
('consumed', '=', True), ('rating', '>=', 1),
]
ratings = request.env['rating.rating'].search(domain, order='create_date desc', limit=100)
repartition = channel.sudo().channel_ids.rating_get_grades(domain=domain)

# compute percentage
percentage = dict.fromkeys(['great', 'okay', 'bad'], 0)
for grade in repartition:
percentage[grade] = repartition[grade] * 100 / sum(repartition.values()) if sum(repartition.values()) else 0
percentage[grade] = round(repartition[grade] * 100.0 / sum(repartition.values()), 1) if sum(repartition.values()) else 0

# the value dict to render the template
values = {
Expand Down
17 changes: 17 additions & 0 deletions doc/cla/corporate/shine-it.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
China, 2018-04-28

Shine IT agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.

I declare that I am authorized and able to make this agreement and sign this
declaration.

Signed,

Tony Gu [email protected] https://github.com/digitalsatori

List of contributors:
Tony Gu [email protected] https://github.com/digitalsatori
Joshua Jan [email protected] https://github.com/joshuajan
Xiao Guo [email protected] https://github.com/xerxesnoPT

11 changes: 11 additions & 0 deletions doc/cla/individual/Zelwak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


France, 2018-06-07

I here by agree to the terms of the Odoo Individual Contributor License Agreement v1.0.

I declare that I am authorized and able to make this agreement and sign this declaration.

Signed,

Flavien CHÊNE [email protected] https://github.com/Zelwak
11 changes: 11 additions & 0 deletions doc/cla/individual/mduvergey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
France, 2018-05-24

I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.

I declare that I am authorized and able to make this agreement and sign this
declaration.

Signed,

Martin Duvergey [email protected] https://github.com/mduvergey
11 changes: 11 additions & 0 deletions doc/cla/individual/schout-it.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Belgium, 2018-05-17

I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.

I declare that I am authorized and able to make this agreement and sign this
declaration.

Signed,

Rod Schouteden [email protected] https://github.com/schout-it
2 changes: 1 addition & 1 deletion doc/setup/enterprise.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ On Linux, using an installer

.. code-block:: console
$ python3 /usr/bin/odoo.py -d <database_name> -i web_enterprise --stop-after-init
$ python3 /usr/bin/odoo-bin -d <database_name> -i web_enterprise --stop-after-init
* You should be able to connect to your Odoo Enterprise instance using your usual mean of identification.
You can then link your database with your Odoo Enterprise Subscription by entering the code you received
Expand Down
6 changes: 4 additions & 2 deletions odoo/addons/base/ir/ir_mail_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
_logger = logging.getLogger(__name__)
_test_logger = logging.getLogger('odoo.tests')

SMTP_TIMEOUT = 60


class MailDeliveryException(except_orm):
"""Specific exception subclass for mail delivery errors"""
Expand Down Expand Up @@ -225,9 +227,9 @@ def connect(self, host=None, port=None, user=None, password=None, encryption=Non
"You could use STARTTLS instead. "
"If SSL is needed, an upgrade to Python 2.6 on the server-side "
"should do the trick."))
connection = smtplib.SMTP_SSL(smtp_server, smtp_port)
connection = smtplib.SMTP_SSL(smtp_server, smtp_port, timeout=SMTP_TIMEOUT)
else:
connection = smtplib.SMTP(smtp_server, smtp_port)
connection = smtplib.SMTP(smtp_server, smtp_port, timeout=SMTP_TIMEOUT)
connection.set_debuglevel(smtp_debug)
if smtp_encryption == 'starttls':
# starttls() will perform ehlo() if needed first
Expand Down
5 changes: 5 additions & 0 deletions odoo/addons/base/res/res_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,11 @@ def _update_user_groups_view(self):
xml = E.field(E.group(*(xml1), col="2"), E.group(*(xml2), col="4"), name="groups_id", position="replace")
xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS"))
xml_content = etree.tostring(xml, pretty_print=True, encoding="unicode")
if not view.check_access_rights('write', raise_exception=False):
# erp manager has the rights to update groups/users but not
# to modify ir.ui.view
if self.env.user.has_group('base.group_erp_manager'):
view = view.sudo()

new_context = dict(view._context)
new_context.pop('install_mode_data', None) # don't set arch_fs for this computed view
Expand Down
2 changes: 1 addition & 1 deletion odoo/addons/base/security/base_security.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
<field name="name">res.partner.rule.private.employee</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="domain_force">
[('type', '!=', 'private')]
['|', ('type', '!=', 'private'), ('type', '=', False)]
</field>
<field name="groups" eval="[
(4, ref('base.group_user')),
Expand Down
2 changes: 1 addition & 1 deletion odoo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3940,7 +3940,7 @@ def copy(self, default=None):
vals = self.copy_data(default)[0]
# To avoid to create a translation in the lang of the user, copy_translation will do it
new = self.with_context(lang=None).create(vals)
self.copy_translations(new)
self.with_context(from_copy_translation=True).copy_translations(new)
return new

@api.multi
Expand Down
5 changes: 4 additions & 1 deletion odoo/service/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,10 @@ def watchdog(self, beat=4):

def start(self):
import gevent
from gevent.wsgi import WSGIServer
try:
from gevent.pywsgi import WSGIServer
except ImportError:
from gevent.wsgi import WSGIServer


if os.name == 'posix':
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def py2exe_options():
'dist_dir': 'dist',
'packages': [
'asynchat', 'asyncore',
'BeautifulSoup',
'commands',
'dateutil',
'decimal',
Expand Down

0 comments on commit e3658d6

Please sign in to comment.