[MERGE] forward port branch saas-11.3 up to 0c42a607ec

This commit is contained in:
Christophe Simonis
2019-02-06 11:59:44 +01:00
17 changed files with 183 additions and 20 deletions
+5
View File
@@ -983,6 +983,11 @@ class AccountTax(models.Model):
if self.amount_type in ('percent', 'division') and self.amount != 0.0 and not self.description:
self.description = "{0:.4g}%".format(self.amount)
@api.onchange('amount_type')
def onchange_amount_type(self):
if self.amount_type is not 'group':
self.children_tax_ids = [(5,)]
@api.onchange('account_id')
def onchange_account_id(self):
self.refund_account_id = self.account_id
+6 -1
View File
@@ -127,7 +127,12 @@ class AccountInvoice(models.Model):
def _get_outstanding_info_JSON(self):
self.outstanding_credits_debits_widget = json.dumps(False)
if self.state == 'open':
domain = [('account_id', '=', self.account_id.id), ('partner_id', '=', self.env['res.partner']._find_accounting_partner(self.partner_id).id), ('reconciled', '=', False), '|', ('amount_residual', '!=', 0.0), ('amount_residual_currency', '!=', 0.0)]
domain = [('account_id', '=', self.account_id.id),
('partner_id', '=', self.env['res.partner']._find_accounting_partner(self.partner_id).id),
('reconciled', '=', False),
'|',
'&', ('amount_residual_currency', '!=', 0.0), ('currency_id','!=', None),
'&', ('amount_residual_currency', '=', 0.0), '&', ('currency_id','=', None), ('amount_residual', '!=', 0.0)]
if self.type in ('out_invoice', 'in_refund'):
domain.extend([('credit', '>', 0), ('debit', '=', 0)])
type_payment = _('Outstanding credits')
@@ -508,7 +508,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
}
return this.model.makeRecord('account.bank.statement.line', [field], {
partner_id: {
domain: [["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
domain: ["|", ["is_company", "=", true], ["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
options: {
no_open: true
}
@@ -29,6 +29,7 @@ var db = {
customer: {string: "customer", type: 'boolean'},
supplier: {string: "supplier", type: 'boolean'},
parent_id: {string: "Parent", type: 'boolean'},
is_company: {string: "Is company", type: 'boolean'},
property_account_receivable_id: {string: 'Account receivable', type: 'many2one', relation: 'account.account'},
property_account_payable_id: {string: 'Account payable', type: 'many2one', relation: 'account.account'},
},
+1 -1
View File
@@ -1937,7 +1937,7 @@ class MailThread(models.AbstractModel):
if False/0, mail.message model will also be set as False
:param str body: body of the message, usually raw HTML that will
be sanitized
:param str type: see mail_message.type field
:param str type: see mail_message.message_type field
:param int parent_id: handle reply to a previous message by adding the
parent partners to the message in case of private discussion
:param tuple(str,str) attachments or list id: list of attachment tuples in the form
+2 -5
View File
@@ -16,13 +16,10 @@ class ResPartner(models.Model):
def _compute_sale_order_count(self):
sale_data = self.env['sale.order'].read_group(domain=[('partner_id', 'child_of', self.ids)],
fields=['partner_id'], groupby=['partner_id'])
# read to keep the child/parent relation while aggregating the read_group result in the loop
partner_child_ids = self.read(['child_ids'])
mapped_data = dict([(m['partner_id'][0], m['partner_id_count']) for m in sale_data])
for partner in self:
# let's obtain the partner id and all its child ids from the read up there
item = next(p for p in partner_child_ids if p['id'] == partner.id)
partner_ids = [partner.id] + item.get('child_ids')
# let's obtain the partner id and all its child ids
partner_ids = [partner.id] + partner.child_ids.ids
# then we can sum for all the partner's child
partner.sale_order_count = sum(mapped_data.get(child, 0) for child in partner_ids)
+1 -1
View File
@@ -69,7 +69,7 @@ class CrmTeam(models.Model):
('order_line.qty_to_invoice', '>', 0),
], ['team_id'], ['team_id'])
for datum in sale_order_data:
self.browse(datum['team_id'][0]).invoiced = datum['team_id_count']
self.browse(datum['team_id'][0]).sales_to_invoice_count = datum['team_id_count']
@api.multi
def _compute_invoiced(self):
+1 -1
View File
@@ -397,7 +397,7 @@ class StockMove(models.Model):
# Get the standard price
amount_unit = std_price_update.get((move.company_id.id, move.product_id.id)) or move.product_id.standard_price
qty = forced_qty or qty_done
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + qty_done)
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + qty)
tmpl_dict[move.product_id.id] += qty_done
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
@@ -2621,6 +2621,46 @@ class TestStockValuation(TransactionCase):
self.assertAlmostEqual(self.product1.standard_price, 7.5)
def test_average_perpetual_7(self):
""" Test edit in the past. Receive 5@10, receive 10@20, edit the first move to receive
15 instead.
"""
self.product1.product_tmpl_id.cost_method = 'average'
move1 = self.env['stock.move'].create({
'name': 'IN 5@10',
'location_id': self.supplier_location.id,
'location_dest_id': self.stock_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 5,
'price_unit': 10,
})
move1._action_confirm()
move1.quantity_done = 5
move1._action_done()
self.assertAlmostEqual(self.product1.standard_price, 10)
move2 = self.env['stock.move'].create({
'name': 'IN 10@20',
'location_id': self.supplier_location.id,
'location_dest_id': self.stock_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 10,
'price_unit': 20,
})
move2._action_confirm()
move2.quantity_done = 10
move2._action_done()
self.assertAlmostEqual(self.product1.standard_price, 16.67)
move1.move_line_ids.qty_done = 15
self.assertAlmostEqual(self.product1.standard_price, 14.0)
def test_average_negative_1(self):
""" Test edit in the past. Receive 10, send 20, edit the second move to only send 10.
"""
@@ -14,6 +14,12 @@ class PurchaseOrderLine(models.Model):
re['sale_line_id'] = self.sale_line_id.id
return res
def _merge_in_existing_line(self, product_id, product_qty, product_uom, location_id, name, origin, values):
if values.get('route_ids') and values['route_ids'] == self.env.ref('stock_dropshipping.route_drop_shipping'):
return False
return super(PurchaseOrderLine, self)._merge_in_existing_line(
product_id=product_id, product_qty=product_qty, product_uom=product_uom,
location_id=location_id, name=name, origin=origin, values=values)
class StockRule(models.Model):
_inherit = 'stock.rule'
@@ -347,7 +347,11 @@ var BooleanField = SelectionField.extend(/** @lends instance.web.search.BooleanF
var DateField = Field.extend(/** @lends instance.web.search.DateField# */{
value_from: function (facetValue) {
var serverFormat = (this.attrs && this.attrs.type === 'datetime') ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
return facetValue.get('valueAsMoment').clone().format(serverFormat);
if (facetValue.get('valueAsMoment')) {
return facetValue.get('valueAsMoment').clone().format(serverFormat);
} else {
return moment(facetValue.get('value')).format(serverFormat);
}
},
complete: function (needle) {
// Make sure the needle has a correct format before the creation of the moment object. See
@@ -52,7 +52,6 @@
}
&:not(:empty)::after {
margin-left: 6px;
position: absolute;
}
&.o-sort-up {
cursor: n-resize;
@@ -4,7 +4,7 @@ odoo.define('website_event.geolocation', function (require) {
var sAnimation = require('website.content.snippets.animation');
sAnimation.registry.visitor = sAnimation.Class.extend({
selector: '.oe_country_events',
selector: ".oe_country_events, .country_events",
/**
* @override
+11
View File
@@ -0,0 +1,11 @@
Sudan, 2019/1/31
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,
Obay obayit@gmail.com https://github.com/obayit
+1 -1
View File
@@ -84,7 +84,7 @@ to manage followers on your record:
:param str body: body of the message, usually raw HTML that will
be sanitized
:param str message_type: see mail_message.type field
:param str message_type: see mail_message.message_type field
:param int parent_id: handle reply to a previous message by adding the
parent partners to the message in case of private discussion
:param list(tuple(str,str)) attachments: list of attachment tuples in the form
+82
View File
@@ -4,6 +4,7 @@
import unittest
import odoo
from odoo.sql_db import TestCursor
from odoo.tests import common
from odoo.tools.misc import mute_logger
@@ -29,3 +30,84 @@ class TestExecute(unittest.TestCase):
cr.execute("SELECT id FROM res_users WHERE id=%s", 1)
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE id=%s", '1')
class TestTestCursor(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestTestCursor, cls).setUpClass()
r = registry()
r.enter_test_mode(r.cursor())
@classmethod
def tearDownClass(cls):
r = registry()
r.test_cr.close()
r.leave_test_mode()
super(TestTestCursor, cls).tearDownClass()
def setUp(self):
super(TestTestCursor, self).setUp()
self.record = self.env['res.partner'].create({'name': 'Foo'})
def write(self, record, value):
record.ref = value
def check(self, record, value):
self.assertEqual(record.read(['ref'])[0]['ref'], value)
def test_single_cursor(self):
""" Check the behavior of a single test cursor. """
self.assertIsInstance(self.cr, TestCursor)
self.write(self.record, 'A')
self.cr.commit()
self.write(self.record, 'B')
self.cr.rollback()
self.check(self.record, 'A')
self.write(self.record, 'C')
self.cr.rollback()
self.check(self.record, 'A')
def test_sub_commit(self):
""" Check the behavior of a subcursor that commits. """
self.assertIsInstance(self.cr, TestCursor)
self.write(self.record, 'A')
self.cr.commit()
self.write(self.record, 'B')
# check behavior of a "sub-cursor" that commits
with self.registry.cursor() as cr:
self.assertIsInstance(cr, TestCursor)
record = self.record.with_env(self.env(cr=cr))
self.check(record, 'B')
self.write(record, 'C')
self.check(self.record, 'C')
self.cr.rollback()
self.check(self.record, 'A')
def test_sub_rollback(self):
""" Check the behavior of a subcursor that rollbacks. """
self.assertIsInstance(self.cr, TestCursor)
self.write(self.record, 'A')
self.cr.commit()
self.write(self.record, 'B')
# check behavior of a "sub-cursor" that rollbacks
with self.assertRaises(ValueError):
with self.registry.cursor() as cr:
self.assertIsInstance(cr, TestCursor)
record = self.record.with_env(self.env(cr=cr))
self.check(record, 'B')
self.write(record, 'C')
raise ValueError(42)
self.check(self.record, 'B')
self.cr.rollback()
self.check(self.record, 'A')
+19 -6
View File
@@ -802,7 +802,7 @@ class Worker(object):
if e.args[0] not in [errno.EINTR]:
raise
def process_limit(self):
def check_limits(self):
# If our parent changed sucide
if self.ppid != os.getppid():
_logger.info("Worker (%s) Parent changed", self.pid)
@@ -819,6 +819,7 @@ class Worker(object):
set_limit_memory_hard()
def set_limits(self):
# SIGXCPU (exceeded CPU time) signal handler will raise an exception.
r = resource.getrusage(resource.RUSAGE_SELF)
cpu_time = r.ru_utime + r.ru_stime
@@ -851,17 +852,18 @@ class Worker(object):
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
signal.set_wakeup_fd(self.wakeup_fd_w)
self.set_limits()
def stop(self):
pass
def run(self):
try:
self.start()
while self.alive:
self.process_limit()
self.multi.pipe_ping(self.watchdog_pipe)
self.sleep()
self.process_work()
t = threading.Thread(name="Worker %s (%s) workthread" % (self.__class__.__name__, self.pid), target=self._runloop)
t.daemon = True
t.start()
t.join()
_logger.info("Worker (%s) exiting. request_count: %s, registry count: %s.",
self.pid, self.request_count,
len(odoo.modules.registry.Registry.registries))
@@ -871,6 +873,17 @@ class Worker(object):
# should we use 3 to abort everything ?
sys.exit(1)
def _runloop(self):
try:
while self.alive:
self.multi.pipe_ping(self.watchdog_pipe)
self.sleep()
self.process_work()
self.check_limits()
except:
_logger.exception("Worker %s (%s) Exception occured, exiting...", self.__class__.__name__, self.pid)
sys.exit(1)
class WorkerHTTP(Worker):
""" HTTP Request workers """
def process_request(self, client, addr):